Skip to main content

Full text of "THINK Pascal User Manual 1991"

See other formats


IHINK Pascal" 

r he Fastest Way to Finished Software 


User 
Manual ♦ 





THINK Pascal" 

The Fastest Way to Finished Software. 

USER MANUAL 



Credits 

User Manual Philip Borenstein and Jeff Mattson 

THINK Pascal Application Rich Siegel, John McEnerney, and David Neal, 

THINK Clas s Library Don Pod wall and Gregory H. Dow 

Quality Assurance David Allcott, Michael Rockhold, and Paul Vetri 

Technical Support Michael Carland, Mark Geschelin, Phil Shapiro 

Marketing Manager Susan Smith 

Product Manager Philip Borenstein 

Copyright © 1988, 1990, 1991 Symantec Corporation. All Rights Reserved. Printed in U.S.A. 

Symantec Corporation THINK C and THINK Pascal are trademarks of Symantec 

10201 Torre Avenue Corporation. Other brands and their products are trademarks of 

Cupertino, CA 95014 their respective holders and should be noted as such. 

408/253-9600 

ResEdit, SARez, and SADeRez are copyrighted programs of Apple Computer, Inc. licensed to Symantec Corp. 
to distribute for use only in combination with THINK Pascal. Apple software shall not be copied onto another 
diskette (except for archive purposes) or into memory unless as part of execution of THINK Pascal. When 
THINK Pascal has completed execution, Apple Software shall not be used by any other program. 

The THINK Pascal User Manual is copyrighted and all rights reserved. Information in this document is subject 
to change without notice and does not represent a commitment on the part of Symantec Corporation. The 
software described in this document is furnished under a license agreement. The document may not, in whole 
or in part, be copied, photocopied, reproduced, translated, or reduced to any electronic medium or machine- 
readable form without prior consent, in writing, form Symantec Corporation. The THINK Pascal User Manual 
contains samples of names and addresses to illustrate features and capabilities of THINK Pascal. Any 
similarities to names and addresses of actual individuals is purely coincidental. 

Symantec Corporation makes no warranties, either express or implied, regarding the enclosed computer 

SOFTWARE PACKAGE, ITS MERCHANTABILITY, OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. THE EXCLUSION OF IMPLIED 
WARRANTIES IS NOT PERMITTED BY SOME STATES. THE ABOVE EXCLUSION MAY NOT APPLY TO YOU. THIS WARRANTY PROVIDES 
YOU WITH SPECIFIC LEGAL RIGHTS. THERE MAY BE OTHER RIGHTS THAT YOU MAY HAVE WHICH VARY FROM STATE TO STATE. 


Contents 


ONE GETTING STARTED 


1 Welcome.3 

Introduction.3 

What is THINK Pascal?.3 

What You Need. 5 

What’s in the Package.5 

What’s in the Manuals.6 

What You Should Know.9 

2 Installing THINK Pascal.13 

Introduction. 13 

Summary. 13 

Instructions. 14 

What’s in the Archives. 1 6 

Disk Layout Diagram. 18 

About the Self-Extracting Archives. 18 

TWO LEARNING THINK PASCAL 

3 Tutorial: Bullseye.21 

Introduction. 21 

Creating the Project.22 

Writing a Source File.26 

Running the Program.28 

Debugging the Program.29 

Stepping Through the Program. 32 

Where to Go Next.33 

4 Tutorial: ObjectDraw.35 

Introduction. 35 

Creating the Project.36 

Adding the Libraries.37 

Adding the Source Files.40 

Setting the Run Options.44 

Setting the Compile Options.46 

Running the Project. 47 

Building the Application.47 

Where to Go Next.49 



































5 


THREE 

6 


7 


Tutorial: Hex Dump DA.51 

Introduction.51 

Writing Desk Accessories.52 

Creating the Project.52 

Changing a Library.54 

Adding the Source Files.56 

Setting the Compile Options.59 

Setting the Run Options.62 

Segmenting the Project.63 

Running the Project.67 

Building the Desk Accessory.67 

Where to Go Next.72 

USING THINK PASCAL 

Editing.75 

Introduction.75 

Creating and Opening Files.75 

Working with Windows.76 

Editing Files.78 

Searching and Replacing.83 

Working with Files.86 

Customizing Program Formatting.89 

Using MPW Projector.93 

Working with Projects.95 

Introduction.95 

What Is a Project?.95 

Organizing Your Files.96 

The Project Window.96 

Creating a New Project.98 

Opening an Existing Project.100 

Closing Projects.100 

Adding Files to Projects.101 

Removing Files from Projects.102 

Arranging Files in the Project.102 

Segmenting a Project.103 

Setting the Compiler Options.108 

Getting Information on a Project’s Code & Data Size.109 

Customizing the Project Window.110 

Recovering Corrupted Projects.Ill 








































8 Running Programs.113 

Introduction.113 

Running a Program.113 

When Something Goes Wrong.114 

Stopping Your Program.115 

Compiling, Building, and Linking Without Running.117 

Save Options.117 

Run Options.118 

9 Debugging Programs.121 

Introduction.121 

Debugging in THINK Pascal.122 

Following the Finger.123 

Stepping Through Programs.124 

Stop Signs.124 

Restarting a Stopped Program .126 

The Execution Commands.127 

The Observe window.127 

The Instant window.129 

Examining Compiled Code.129 

10 Units and Libraries.131 

Introduction.131 

Using Units.131 

Writing a Unit.132 

Using Libraries.136 

Writing Libraries.137 

11 Using Predefined Routines.141 

Introduction.141 

Calling Standard Pascal Routines.141 

Calling Macintosh Toolbox Routines.142 

12 Building Projects.147 

Introduction.147 

Setting the Project Type.148 

Using Resource Files.149 

Building Applications.150 

Building Desk Accessories and Device Drivers.151 

Building Code Resources.163 

Putting It Together.171 


V 








































13 


14 


15 


FOUR 

16 


Assembly Language.173 

Introduction.173 

The Runtime Environment.174 

Pascal Data Types.176 

Pascal Calling Conventions.180 

Using Assembly Language.182 

LightsBug.185 

Introduction.185 

Using LightsBug.186 

Examining Subroutines.188 

Examining Variables.191 

Examining Structured Variables.192 

Examining Many Variables.194 

Using Watchpoints.194 

Editing Variables.195 

Type Casting Variables.195 

Examining Registers.196 

Examining Heap Zones.197 

Displaying Memory.198 

Editing Memory.200 

Debugging Toolbox Routines.201 

Compiler Directives.203 

Introduction.203 

What Are Compiler Directives?.204 

Using Compiler Directives.207 

Using Conditional Compilation.214 

Using the Compile Options... Command.215 

REFERENCE 

THINK Pascal Menus.223 

Introduction.223 

The Apple Menu.223 

The File Menu.224 

The Edit Menu.228 

The Search Menu.233 

The Project Menu.236 

The Run Menu.246 

The Debug Menu.250 

The Windows Menu.252 


vi 








































17 Language Reference.255 

Introduction.255 

1.0 Tokens and Constants.257 

2.0 Blocks, Scopes, and Activations.262 

3.0 Types.266 

4.0 Variables.283 

5.0 Expressions.287 

6.0 Statements.301 

7.0 Procedures and Functions.315 

8.0 Programs and Units.327 

9.0 Input/Output.331 

10.0 Standard Procedures and Functions.353 

FIVE UTILITIES 

18 Project Utilities.379 

Introduction.379 

Using Project Utilities.379 

Selecting Files.383 

Printing Files.384 

Backing Up Files.386 

19 The Profiler.391 

Introduction.391 

Using the Profiler.391 

Reading the Report.392 

Summary.393 

20 The Pascal Source Converter.395 

Introduction.395 

Scripts.395 

Input and Output Directories.396 

Specifying Directories and File Names.396 

Converting Files.397 

Pascal Source Converter Directives.400 

A Sample Script.404 

21 Resource Description Files.405 

Introduction.405 

The Resource Compiler and Decompiler.406 

Structure of a Resource Description File.407 

Resource Description Statements.409 

Labels.425 

Preprocessor Directives.431 

Resource Description Syntax.434 










































22 Using SARez.441 

Introduction.441 

What Is SARez?.441 

Choosing Input Files.443 

Choosing an Output File.444 

Setting Options.446 

Saving and Restoring Options.450 

The Messages Window.451 

23 Using SADe Rez.453 

Introduction.453 

What Is SADeRez?.453 

Choosing Input Files.455 

Choosing Output Files.457 

Setting Options.458 

Saving and Restoring Options.460 

The Messages Window.461 

24 Using SAPostRez.463 

Introduction.463 

What is SAPostRez?.463 

Using SAPostRez.463 

SIX APPENDICES 

A What’s New.467 

Introduction.467 

Compatibility with Earlier Releases.467 

System 7.0 Compatibility.467 

Working with Large Projects.468 

Working with Small Projects.468 

New and Improved Commands.470 

Enhanced THINK Class Library.473 

Other Changes.473 

B ANS Pascal Compatibility.475 

Introduction.475 

Exceptions to ANS Pascal Requirements.475 

Extensions to ANS Pascal.476 

Implementation-Dependent Features.478 

Treatment of Errors.478 






































c 


Porting to THINK Pascal.481 

Introduction.481 

Identifier Length.482 

Reserved Words.482 

Comments and Directives.482 

The Uses Clause.483 

Types.484 

Data Representation.484 

Data Initialization.486 

Operators.486 

Integer Arithmetic.486 

Program Parameters.487 

Predefined Procedures and Functions.487 

Standard Units.488 

Input/Output.489 

Run Time Environment.490 

Extensions.490 

Using .o Files.492 

D Error Messages.493 

Index.563 


IX 
























THINK Pascal' 

PART ONE 

Getting Started 

1 Welcome 

2 Installing THINK Pascal 





Welcome 

1 


Introduction 

Welcome to THINK Pascal. This chapter tells you about THINK Pascal, what’s in your THINK 
Pascal package, what equipment you need, and what you need to know to start writing Pascal 
programs on the Macintosh. 

Before you begin 

Be sure to fill out and return the registration card that came with your THINK Pascal package. 
Registering insures that you’ll get the technical support you need and that you’ll be notified of revi¬ 
sions and upgrades to THINK Pascal. Be sure to keep a copy of the serial number for your copy of 
THINK Pascal in this manual (or some other place where you can be sure you won’t lose it). You’ll 
find the serial number on your registration card. 

If you don’t read manuals 

To get started quickly, read this chapter, the next chapter, and do one of the tutorials. 

If you’re an experienced THINK Pascal user 

If you already use THINK Pascal, you’ll be pleased with the new features in this release. Read 
Appendix A, “What’s New,” to learn about all the new features in THINK Pascal 4.0. 

Topics covered In this chapter 

• What is THINK Pascal 

• What you need 

• What’s in the package 

• What’s in the manuals 

• What you should know 

What is THINK Pascal? 

THINK Pascal is a unique development environment for the Macintosh. It features a very fast 
compiler, a faster linker, an integrated text editor designed specifically for Pascal syntax, an auto¬ 
make facility, advanced debugging tools, a class library, a class browser, and a project organizer 
that holds all the pieces together. Because the editor, the compiler, and the linker are all compo¬ 
nents of the same application, THINK Pascal knows when edited source files need to be re¬ 
compiled. If you edit the interface section of a unit, the auto-make facility recompiles only the 
source files that depend on it. 



THINK Pascal User Manual 


With THINK Pascal you can build Macintosh applications, desk accessories, device drivers, and any 
kind of code resource. The standard Pascal libraries include standard I/O functions like writeln 
so you can use Pascal programs that were written for other computers. 

THINK Pascal lets you run your program as you work on it. Your program runs as if you had 
opened it from the Finder. You can use the debugging tools built into THINK Pascal to make sure 
your program runs correctly. The debugger lets you set breakpoints, step through your code, ex¬ 
amine variables, and change their values—even structured variables like records and arrays— 
while your program is running. 

THINK Pascal is fast. So fast that it will change the way you program. Not only are the compiler and 
the linker many times faster than other development systems, they are part of an integrated pack¬ 
age that also includes an editor, debuggers, an automatic project manager that keeps track of your 
edits and only recompiles source Files that have changed since the program was last built. 

THINK Pascal is a remarkable product that delivers the efficiency and power you need. THINK 
Pascal will seem natural and obvious—the way things ought to be. 

A development environment that works with you 

In traditional development environments, the edit-compile-link-run cycle takes so long that it’s im¬ 
practical to make a small change just to see how it works. Because it takes so long to compile and 
link, programmers tend to make several changes at once to get more “bang for the buck.” 
Unfortunately, when your program crashes, you have to figure out which one of the small changes 
actually caused the crash. The “bang” gets very expensive. 

Because THINK Pascal is so fast, you can make a small change, compile and link your program, 
and run it to see the effect before a traditional development environment even starts linking. And 
because your program is running in the controlled THINK Pascal environment, you don’t have to 
worry about most of the common crashes. THINK Pascal is right there to catch you so you can start 
fixing your code without restarting your Macintosh. 

In traditional development environments, you have to keep track of various components such as 
source files, object files, a link-control file, an executable image, and administrative files. THINK 
Pascal takes care of all this bookkeeping for you. In THINK Pascal, you have only your source files, 
library files, and a project document The project document serves as an on-line project adminis¬ 
trator for your program development. THINK Pascal keeps track of whatever changes you make to 
your source files, automatically compiling and linking wherever necessary, so all you have to do is 
edit your program and run. 

A rich set of debugging tools 

Not only does THINK Pascal help you develop your program faster, it also helps you debug your 
program faster. THINK Pascal has a rich set of powerful debugging tools. 

The integrated editor catches syntax errors and pretty-prints (formats) your program as you type it 
in. THINK Pascal lets you run your program a statement at a time or in slow motion. You can stop 
your program any time it’s running, or you can set breakpoints anywhere in your program. 


4 



Welcome 


1 


The Observe and LightsBug windows let you examine and change the values of your variables — 
even structured variables like records and arrays. The Instant window lets you try out small pieces 
of code to see how they’d work in your program. 

Advanced features let you stop at Macintosh Toolbox routines, and you can even use a low level 
debugger like TMON or Macsbug. 

A class library that Implements an Interface for you 

The THINK Class Library is a collection of classes that implement the core of a standard Macintosh 
application. The THINK Class Library implements all the standard features of a Macintosh applica¬ 
tion and makes writing Macintosh applications easier. 

What You Need 

THINK Pascal works best when you have at least 1 megabyte (Mb) of RAM and a hard disk. With 
only 1Mb, you won’t be able to take advantage of System 7.0, MultiFinder, the THINK Class Library, 
or MacApp. 

Which Macintosh models? 

You can run THINK Pascal on a Macintosh Classic, Plus, SE, Portable, the Macintosh SE series, or 
the Macintosh II series. 

Which System and Finder? 

Use the latest System and Finder provided by Apple. THINK Pascal requires at least System 6.0.5. 

THINK Pascal is designed to work best under MultiFinder or System 7.0. If you’re using a 
Macintosh with 1MB RAM, you’re better off using the latest version of System 6.0 recommended for 
your machine with MultiFinder turned off. 

How much RAM? 

Under System 6,.you can run THINK Pascal with 1MB of RAM. To use the THINK Class Library, you 
need 2MB. To use MacApp, you need 4MB. 

Under System 7.0, you can run THINK Pascal with 2MB of RAM. To use the THINK Class Library or 
MacApp , you need 4MB. 

How much disk space? 

The basic THINK Pascal system takes up about 1200K on your disk, not including your own files. 
The size of the whole THINK Pascal system is 5.75 megabytes. The actual size of your system may 
be smaller, depending on the kinds of programs you work on. 

What’s in the Package 

Your THINK Pascal package consists of four disks, this manual (THINK Pascal User Manual), and 
the Object-Oriented Programming Manual . In addition to THINK Pascal, the disks contain the 


5 



THINK Pascal User Manual 


THINK Class Library, several programming examples, and some utilities, like the THINK Pascal 
profiler, ResEdit, SARez, and SADeRez. 

What’s in the Manuals 

The two manuals describe different parts of your THINK Pascal package. This manual, the THINK 
Pascal User Manual , tells you how to use THINK Pascal. The Object-Oriented Programming 
Manual describes Object Pascal in THINK Pascal and the THINK Class Library in detail. 

Conventions In the manuals 

Each chapter begins with an introduction that describes what’s in the chapter, followed by a list of 
the major topics covered in the chapter. If you are interested in a specific topic, consult the index in 
the back of the manual. 

The names of menus and commands are in bold face. 

When a technical term or key word is introduced, it also appears in bold face. 

Names of files, code fragments, resource names, function names, and variables appear in 
“typewriter face.” 

All numbers are decimal. Hexadecimal numbers are written in Pascal notation: $3EFA. 

In these manuals, the term Toolbox routine means any routine in ROM. The Macintosh ROM ac¬ 
tually consists of two kinds of routines: Operating System routines and Toolbox routines. 

Operating System routines deal with low-level aspects of the machine like the file manager, the 
event posting mechanism, device management, etc. The Toolbox deals with high-level aspects like 
the drawing environment, the window mechanism, menus, dialogs, etc. 

THINK Pascal User Manual 

This manual is organized in six sections: Getting Started, Learning THINK Pascal, Using THINK 
Pascal, Reference, Utilities, and Appendices. 

ONE Getting Started 

This section contains this chapter and the installation instructions. 

1 Welcome gives you an overview of THINK Pascal. This is the chapter you’re reading 

2 Installing THINK Pascal shows you how to install THINK Pascal. Even if you don’t 
read manuals, be sure to read these instructions. 

TWO Learning THINK Pascal 

This section contains three tutorials. 

3 TutoriaLBullseye shows you how to write a program in THINK Pascal and how to use 
the basic debugging tools. 


6 



Welcome 


1 


4 TutorialiObjectDraw shows you how to build a Macintosh application in THINK 
Pascal. It covers some of the more advanced topics like using resource files and libraries. 

5 Tutorial: Hex Dump DA shows you how to build a desk accessory in THINK Pascal. It 
covers even more advanced topics like segmentation. 

THREE Using THINK Pascal 

This section contains ten chapters that describe the different components of THINK 
Pascal. 

6 Editing describes the THINK Pascal editor which is specifically designed to help you 
write Pascal programs. 

7 Working With Projects is about projects, the tool that keeps track of all your source 
files and object code. You’ll learn how to work with source files, how to add them to 
your project, and how to segment your project. 

8 Running Programs shows you how to run a program in THINK Pascal. You’ll learn 
how to compile and link your program, and what to do when something goes wrong. 

9 Debugging Programs introduces you to the basic set of debugging tools in THINK 
Pascal. These tools let you run your program line by line, set breakpoints anywhere in 
your program, and observe the values of your variables. 

10 Units and Libraries teaches you how to create units and libraries. Units and libraries 
are collections of Pascal code that help you write modular programs. 

11 Using Predefined Routines tells you how to use the procedures and functions built 
into THINK Pascal. It also tells you how to call the Macintosh Toolbox routines. 

12 Building Projects shows you how to build the four kinds of programs you can write in 
THINK Pascal: applications, desk accessories, device drivers, and code resources. 

13 Assembly Language gives you all the information you need to know to write assembly 
language routines that work with THINK Pascal. 

14 LightsBug introduces you to LightsBug, THINK Pascal’s powerful debugging tool. 
LightsBug lets you get a closer look at your program. You can examine and change the 
values of your variables (even arrays and records), look at any part of memory, and 
examine the heap. 

15 Compiler Directives shows you how to use compiler directives — instructions to the 
compiler — to generate different code for different situations. 



THINK Pascal User Manual 


FOUR Reference 

This section contains two reference chapters. 

16 THINK Pascal Menus describes the THINK Pascal menu commands. 

17 Language Reference describes the Pascal language implemented by THINK Pascal. 

This is a very long chapter, and you don’t have to read all of it. The important sections 
are sections 9 and 10 which describe the built in input/output routines and the standard 
routines. 

FIVE Utilities 

This section describes how to use several utilities that come with THINK Pascal 

18 Project Utilities describes a utility that can back up or print the files in your project. 

19 The Profiler shows you how to use the THINK Pascal profiler to see how your program 
runs and how much time is spent in each routine 

20 The Pascal Source Converter helps translate programs written for Apple’s MPW Pascal 
for use with THINK Pascal. 

21 Resource Description Files describes How to write text files that you compile with 
SARez to produce resource files. 

22 SARez creates resource files from resource description files. 

23 SADeRez creates resource description files from resource files 

24 PostRez converts a resource file for use with a MacApp program 

SIX Appendices 

This section contains four appendices. 

A What’s New describes the new features in THINK Pascal 4.0. 

B ANS Pascal Compatibility describes THINK Pascal’s compatibility with the ANS Pascal 
standard. 

C Porting to THINK Pascal describes the limitations and non-standard features of THINK 
Pascal that you need to be aware of when you port programs from other Pascal 
compilers to THINK Pascal. 

D Error Messages lists and describes all the error messages that THINK Pascal generates. 




Welcome 


1 


What You Should Know 

This manual assumes you know how to use your Macintosh, and that you already know or are at 
least learning, how to program in Pascal. If you’re just getting started in Pascal, THINK Pascal is a 
great platform. 

If you’re planning to write Macintosh applications, you should be familiar with the Macintosh 
Toolbox as described in Inside Macintosh. The Toolbox is the set of operating system and user in¬ 
terface routines that make a Macintosh a Macintosh. This manual won’t show you how to write 
Macintosh applications or how to use the Macintosh Toolbox. There are several books that teach 
you how to build applications — see “Learning to write Macintosh programs” below. You can also 
look at the sample programs in your THINK Pascal package for examples of Macintosh 
applications. 

One of the best ways to learn both Pascal and Macintosh programming at the same time is with 
Symantec’s Just Enough Pascal, an on-line programming tutorial. Just Enough Pascal is a desk ac¬ 
cessory that works with THINK Pascal to teach you Pascal, Macintosh programming, and THINK 
Pascal right at your Macintosh. 

Learning Pascal 

Pascal is the most popular language for learning how to program, so you’ll find several books that 
teach programming in Pascal. Some of the Pascal books are written specifically for use with THINK 
Pascal or its cousin, Macintosh Pascal. 

The standard reference for the Pascal programming language is the third edition of Pascal User 
Manual and Report (Springer-Verlag) by Kathleen Jensen and Niklaus Wirth, revised by Andrew 
Mickel and James Miner. The User Manual and Report is fairly technical, and it’s designed for 
people who already know fundamental programming concepts. 

Scott Kronick’s Macintosh Pascal Illustrated: The Fear and Loathing Guide (Addison-Wesley) is an 
amusing and unorthodox introduction to programming the Macintosh in Pascal. His book covers 
most of the things you need to know to get started. 

Oh! THINK’s Lightspeed Pascal (W. W. Norton) by George Beekman and Michael Johnson is a 
companion to Oh! Pascal (WW. Norton) by Doug Cooper and Michael Clancy. Together, these 
books are a good introduction to Pascal and THINK Pascal. 

Pascal on the Macintosh: A Graphical Approach (Addison-Wesley) by David Niguidula and 
Andries Van Dam is for beginning Pascal programmers and uses THINK Pascal examples. Several 
universities use it as a first term programming text. 

Another good book if you’re learning Pascal is Macintosh Pascal (Houghton-Mifflin), by Robert 
Moll and Rachel Folsom. It is particularly helpful because of the many similarities between 
Macintosh Pascal and THINK Pascal. 


9 



THINK Pascal User Manual 


Kurt Schmucker’s Object-Oriented Programming for the Macintosh (Hayden) contains a great deal 
of information about object-oriented programming in general and some details about using Object 
Pascal. 

Object-Oriented Programming Powerfor THINK Pascal Programmers (Microsoft Press) also 
teaches you how to use Object Pascal and is especially for THINK Pascal programmers. It also 
teaches you the fundamentals of application frameworks, like the THINK Class Library and 
MacApp. 

Learning to write Macintosh programs 

If you’re new to programming the Macintosh, you might find yourself overwhelmed by the 
complexity of the Macintosh Toolbox and unfamiliar programming techniques. When the 
Macintosh was introduced in 1984, there was very little technical information available to casual 
programmers, and even commercial developers had a hard time figuring out how to get things to 
work correctly. 

The Macintosh is even more complex today than it was in 1984, but now there are more places you 
can go for information. Several good books introduce programming the Macintosh and teach some 
of the finer points of using the Macintosh Toolbox. No matter which books you choose to get 
started, Inside Macintosh is indispensable. 

Inside Macintosh Volumes I-VI (Addison-Wesley) is the official reference that describes the more 
than 1,000 Macintosh Toolbox routines. You might be able to get by without it for a while, but if 
you’re planning to write serious applications, you just can’t do without it At six volumes, it 
represents a hefty investment. The first three volumes cover the fundamentals. Volumes IV and V 
cover the additions and changes made with the introduction of the Macintosh Plus, SE, and II. 
Volume VI covers the changes introduced with System 7. 

In addition to Inside Macintosh , Apple also publishes these books through Addison-Wesley: 

• Human Interface Guidelines 

• Technical Introduction to the Macintosh Family 

• Programmers Introduction to the Macintosh Family 

• Guide to the Macintosh Family Hardware, Second Edition 

• Apple Numerics Manual, Second Edition 

• LaserWriter Reference 

• Inside AppleTalk 

• Designing Cards and Drivers for the Macintosh Family, Second Edition 

You won’t need all these books when you get started. Some of the books, like Human Interface 
Guidelines , are useful for all Macintosh programmers. Other books, like Inside AppleTalk, are 
meant for programmers working on specific kinds of applications. These books are available from 
APDA , technical bookstores and computer stores, and in some general bookstores. 

THINK Reference, by Symantec, is a hypertext program that gives you instant access to the critical 
system information that you need to program the Macintosh. It describes nearly all of the Macintosh 
Toolbox routines from Inside Macintosh I-V t including information from the technical notes, code 


10 




Welcome 


1 


examples, and Symantec programmer tips. The information is cross-referenced, so you can look up 
related Toolbox routines quickly. It includes customizable bookmarks and templates that let you 
copy Toolbox calls right into your own program. 

The Macintosh Pascal Programming Primer: Inside the Toolbox Using THINK Pascal, Volume 1, by 
Dave Mark is a good introduction to Macintosh programming for those already familiar with Pascal. 
It explains how to use the Toolbox, handle resources, and write a Macintosh application. Also, the 
examples use some of the newer parts of the Macintosh system, such as the Notification Manager 
and HyperCard XCMDs and XFCNs. 

Stephen Chernicoffs four volume set, Macintosh Revealed (Hayden Books), is another step-by-step 
introduction to Macintosh programming. Chemicoff shows you how to build a working application 
and points out the parts of Inside Macintosh you really need to know as opposed to the parts you 
just need to be aware of. The programs in the books are written in MPW Pascal, but they’re not too 
difficult to translate to THINK Pascal or to THINK C. 

Scott Knaster is the author of two books on Macintosh programming. The first, How to Write 
Macintosh Software (Hayden Books), teaches you what goes on inside the Toolbox. This book 
contains some valuable tips about debugging Macintosh programs. The second book, Macintosh 
Programming Secrets (Addison-Wesley), deals with some of the conventions and techniques that 
have become standard in Macintosh programs. It also contains information about the Macintosh II 
and the Macintosh SE. These books are more technical than Macintosh Revealed and are loaded 
with pictures, diagrams, and examples. 

If you frequently use ResEdit to create and edit resource files, you may want the ResEdit 2.1 
Reference (Addison-Wesley) by Apple Computer, Inc. It explains how to edit standard resource 
types and how to extend ResEdit by adding your own resource pickers and editors. 

Finally, MacTutor is the leading technical journal for Macintosh programming. The articles range 
from tutorial examples to advanced techniques. MacTutor covers several languages, not just C and 
Pascal, and most of the examples are written in THINK C and THINK Pascal. (All of the programs 
described in the magazine are available on disk.) 

Apple Computer, Inc. 

Apple Computer is naturally one of the best places for information about Macintosh programming. 
Apple administers the Apple Partner and Apple Associate program for commercial and non¬ 
commercial software developers. For more information, contact Apple: 

Apple Computer, Inc. 

20525 Mariani Avenue, MS 75-2C 
Cupertino, CA 95014 
(408) 974-4897 

Apple Programmer’s and Developer's Association (APDA) 

The Apple Programmer’s and Developer’s Association (APDA) is Apple’s in-house membership 
organization that distributes technical information to programmers and developers. APDA is a great 


11 




THINK Pascal User Manual 


source for Technical Notes, programming utilities, reference books, and information about 
announced (but unreleased) products. For information about membership and products, contact 
APDA directly: 

Apple Programmer’s and Developers Association (APDA) 

Apple Computer, Inc. 

20525 Mariani Avenue, MS 33G 
Cupertino, CA95014-6299 
(800) 282-2732 (USA) 

(800) 637-0029 (Canada) 

(408) 562-3910 (Other) 

(408) 562-3971 (Fax) 

CompuServe 

Symantec has a forum on CompuServe specifically for its customers. Simply type GO SYMANTEC at 
any ! prompt You’ll find discussions here about programming in general and THINK C and 
THINK Pascal in particular. The data libraries contain utilities as well as sources for many programs. 

CompuServe also has an Apple developers forum. Just type GO MACDEV at any ! prompt. This 
forum is a good place to get in touch with the Macintosh programming community. 

Symantec Programming Languages Association (SPLAsh) 

The Symantec Programming Languages Association (SPLAsh) is a user group for anyone who uses 
the Symantec programming languages THINK C and THINK Pascal. SPLAsh is an independent 
organization endorsed by, but not affiliated with, Symantec Corporation. 

SPLAsh offers its members the following: 

• THINKln’ CaP ; a 100-page quarterly that includes technical articles with source code, 
help for beginners, tips from Symantec Technical Support, insights on the THINK Class 
Library, and reviews of the latest tools and conferences. 

• A quarterly disk containing all the source code from THINKin’ CaP, programming 
utilities, and the latest patches for THINK C and THINK Pascal 

• Meetings at major Macintosh conferences, including seminars on topics of interest and 
presentations from Symantec and SPLAsh members. 

• A SPLAsh forum on America Online. 

Yearly membership is $30 for USA residents, $40 for Canada and Mexico residents, and $60 for 
residents of other countries. For more information, write to this address: 

SPLAsh Resources 
1678 Shattuck Ave., #302 
Berkeley, CA94709 


12 




Installing THINK Pascal 

2 


Introduction 

This chapter tells you how to install THINK Pascal on your Macintosh. 

Before you start... 

Before you install THINK Pascal 4.0, you’ll want to take care of these steps: 

• If there is a file named READ ME on the disk THINK Pascal 1 , read it. It contains 
information that didn’t make it into the THINK Pascal manuals. It’s a text file that you 
can read with any word processor, including Teach Text. 

• Make a copy of your THINK Pascal 4.0 disks. If something goes wrong during the 
installation, you’ll be able to make another copy and continue. 

• Fill out and send in your registration card. You’ll find it in the Customer Service Plan 
envelope. If you want technical support, information about upgrades, or news about 
special promotions, you must become a registered user. 

• Make sure you have at least 5.75 megabytes (5.75MB) of disk space free. If you don’t 
have enough room, either clean up your hard disk, or read “What’s in the Archives” 
later in this chapter and install only the parts of THINK Pascal 4.0 that you need. 

• Some anti-viral software, like Symantec Antivirus for the Macintosh (SAM), may warn 
you when the archive installs an application. If this happens, let the archive continue its 
operation. (In SAM, click Allow) You may want to turn off your anti-viral software 
before you install THINK Pascal 4.0. 

Topics covered in this chapter 

• Summary 

• Before you start... 

• Instructions 

• What’s in the archives 

• Disk layout diagram 

• About the self-extracting archives 

Summary 

This chapter tells you how to set up THINK Pascal on your hard disk. This setup ensures that 
THINK Pascal will know where to find all the files it needs to compile your programs. To learn 
more about why the files are organized this way, see Chapter 9, “Files & Folders.” 

Your THINK Pascal 4.0 disks contain a total of seven self-extracting archives, applications that 
contain compressed files which they decompress and install on your hard disk. You’ll create a 
folder on your hard drive and then run each self-extracting archive and let them install their files in 


13 



THINK Pascal User Manual 


that folder. Then you’ll move the THINK Pascal 4.0 application into the newly created THINK 
Pascal 4.0 Folder. If you want to install only some parts of THINK Pascal 4.0, read “What’s in the 
Archives” later in this chapter to find out which archives you need to run. 

Instructions 

Here’s how to install THINK Pascal 4.0: 

1. In the Finder, create a new folder and name it Development. 

2. Insert the disk THINK Pascal 1, and double-click on THINK Pascal 
Utilities.sea. 

3. A standard file dialog, like the one below, appears. Move to your Development folder 
and click Extract. 


Select Destination Folder: 

<51 Deuelopment | 



4. The archive decompresses its files and places them on your hard disk. It displays its 
progress in the dialog below. The archive quits when it’s done. 

Extracting: Project Utilities 

. 

Files remaining to be extracted: 1 [Cancell 

Compacted by Compact Pro™ AutoExtractor © 1991 Bill Goodman 


14 




Installing THINK Pascal 


2 


5. Repeat steps 2-A for the each of the other archives on THINK Pascal 2, THINK 
Pascal 3, and THINK Pascal 4. 

6. Insert THINK Pascal 1, and move THINK Pascal 4.0 into the THINK Pascal 
4.0 Folder in your Development folder. 

When you’re done, the Development folder contains these folders, as shown below: 

THINK Pascal 4.0 Folder THINK Pascal 4.0 Utilities 

THINK Pascal 4.0 Demos TCL 1.1 Demos 

MacApp 2.0 for THINK Pascal 4.0 



Note: The icons in your folders won’t be in the same places as the icons in this 
illustration. You can arrange them anyway you want inside the folder. 


15 





THINK Pascal User Manual 


What’s in the Archives 

You don’t need to install everything included in your THINK Pascal 4.0 package. This table 
describes which archives you should run to get what you need. 


If you want the... 

Basic THINK Pascal system 


Run these archives... 

Interfaces & Libs.sea on THINK Pascal 2,and 
copy THINK Pascal 4.0 into your THINK Pascal 
4.0 Folder from THINK Pascal 1. 


THINK Class Library 
(Even if you’ve used the 
THINK Class Library before, 
you’ll need the demos for 
examples of the new 
features.) 


THINK Class Library 1.1.sea 
on THINK Pascal 3 and 
TCL 1.1 Pascal Demos.sea 
on THINK Pascal 2. 


Tutorials and example THINK Pascal 4.0 Demos, sea 

programs on THINK Pascal 2. 


Resource utilities, like Resource Utilities . sea on THINK Pascal 4. 

ResEdit and SARez 


Other utility programs, like think Pascal Utilities. sea 
Project Utilities. on THINK Pascal 1. 


MacApp 2.0 support MacApp 2.0 for THINK Pascal. sea 

on THINK Pascal 3. 


The rest of this section describes what’s in each archive. 

Interfaces & Llbs.sea 

This archive places these folders in the THINK Pascal 4.0 Folder: 

• DA Shell 

• Interface.Lib 

• Runtime.Lib 

• Interfaces folder 

• Libraries folder, which includes SANELib. lib, SANELib881. lib, 

^Runtime . Lib, TCLRuntime. Lib, DRVRRuntime. Lib, and RSRCRuntime. Lib. 

THINK Pascal 4.0 Demos.sea 

This archive places these folders in the THINK Pascal 4.0 Demos folder: 

• Hex Dump Folder 

• HyperCard Demos folder 

• LearnOOP folder 

• Ob jectDraw f folder 



Installing THINK Pascal 


2 


THINK Class Library 1.1.sea 

This archive places the THINK Class Library in the THINK Class Library 1.1 folder. 

TCL 1.1 Pascal Demos.sea 

This archive places these folders in the TCL 1.1 Pascal Demos folder: 

• New Class Demo folder 

• Starter folder 

• Tiny Edit folder 

• Art Class Folder 

Resource Utiiities.sea 

This archive places these files in the THINK Pascal 4.0 Utilities folder: 

• ResEdit 2.1 folder 

• Rez Utilities folder, which includes SARez, SADeRez, and SAPostRez. 

THINK Pascal Utiiities.sea 

This archive places this application in the THINK Pascal 4.0 Folder: 

• Project Utilities 

It also places these files in the THINK Pascal 4.0 Utilities folder: 

• AppleEdit 2.0, a text editor desk accessory 

• Block Comment FKEY f folder 

MacApp 2.0 for THINK Pascai.sea 

This archive places these files in the Mac App 2.0 for THINK Pascal 4.0 folder: 

• Pascal Source Converter 

• Generic.Script 

• MacApp.Script 

• MacApp Seeds folder 

• -Samples from MacApp* folder 

It also places the THINK MacApp folder in the THINK Pascal 4.0 Folder, with these files: 

• Dif f s folder 

• MacApp Libraries folder 

• Templates folder 

• Settings.R 

• Settings.Debug.R 


17 



THINK Pascal User Manual 


Disk Layout Diagram 

If you move or rename the folders containing your THINK Pascal files, THINK Pascal can still find 
your files. But you must follow these guidelines: 

• Keep all your THINK Pascal libraries and interfaces in the same (or a nested) folder as 
the THINK Pascal application. 

• Keep all your source files and other project-specific files in the same (or a nested) folder 
as your project document. 

This diagram shows the recommended disk layout. (AboutBox is the name of a program you might 
be working on.) 

(—) 




THINK Pascal 4.0 



Runtime.lib Interface.lib 


Libraries Interfaces 



About the Self-Extracting Archives 

The self-extracting archives included with THINK Pascal 4.0 are created with the shareware 
program Compact Pro. You can open a self-extracting archive with Compact Pro to examine its 
contents or install files one by one. You can download Compact Pro from most on-line services, 
including CompuServe, or write the author for ordering information: 

Bill Goodman 
109 Davis Avenue 
Brookline, MA 02146 
USA 


18 















THINK Pascal' 

PART TWO 

Learning THINK Pascal 

3 Tutorial: Bullseye 

4 Tutorial: ObjectDraw 

5 Tutorial: Hex Dump DA 





Tutorial: Bullseye 

3 


Introduction 

This chapter shows you how to write a program with THINK Pascal. The program, called Bullseye, 
draws a series of concentric circles in the built-in Drawing window. This chapter shows you how to 
create a THINK Pascal project, how to write a Pascal source file, and how to use some of the more 
common debugging tools in THINK Pascal. 

Note: The pictures for this tutorial were made under System 6. The tutorial works 
under System 7.0, but some dialog boxes will look slightly different from those in 
the pictures. 

Before you begin 

Be sure you followed the instructions in Chapter 2, “Installing THINK Pascal,” to install THINK 
Pascal on your disk. 

What you should know 

You should know how to use the standard file dialog boxes to move around to different folders. If 
you don’t know how to do this, read the Macintosh System Software User’s Guide that came with 
your Macintosh. 

Topics covered in this chapter: 

• Creating the project 

• Creating a source file 

• Adding the source file to the project 

• Running the program 

• Debugging the program 

• Stepping through the program 

• Where to go next 



Creating the Project 

To start creating the Bullseye project, double-click on the THINK Pascal icon. You’ll see a dialog 
box that asks you to open a project: 



Since you’re creating a new project, click on the New button. 

You’ll see another dialog box, one that lets you create projects. This is the same dialog you see 
when you select New Project... from within THINK Pascal. 

Move outside the THINK Pascal Folder . 

Note: It’s very important to move outside the THINK Pascal Folder. 


22 





Tutorial: Bullseye 


3 


Check the Instant Project box The Instant Project option helps you create small programs by 
automating many steps. Name the project Bullseye, and click on the Create button. 


€3 Programming | 


CD ObjectDraiv f 

CD THINK Pascal Folder 

O 

o Rkbar 


. tied J 

[ Drive ] 


2 


Create the project: 


( Create J| 

Bullseye 

[ Cancel 


[x] Instant Project 


THINK Pascal creates these things: 

• A source file (Bu 11seye. p) 

• A project file (Bullseye . 7t) that contains the source file 

• A folder (Bullseye f) to hold the project file and the source file. 

Note: If you don’t use the Instant Project option, THINK Pascal creates only the 
project file. You need to create and add your own source file and create your own 
folder to hold them. 

The Instant Project option always creates a source file that ends in .p, a project document 
that ends in . 7t, and a folder that ends in f. It uses what you entered in the New Project... dialog 
as the root for these names. If you entered something ending in . n, it strips that off before creating 
the names. 

Note: You may want to follow this naming convention for your own folders and 
project documents. To type a f press Option-f. To type a n , press Option-p. 


23 





THINK Pascal User Manual 


THINK Pascal displays the project document and source file. If you want, you can resize them so 
they look like this: 


_ Bullseye.TT 

Options File (by build order) 
Runtime .lib 
Interface .lib 
[511 N I V R Bullseye.p 

7SiiTSS3F3& 


Size 

0 

0 

0 

.o 




program Bullseye; 

{ Insert your declarations here } 

begin 

{ Insert your program code here } 

end. 




The source file contains an outline for a program. Its comments show you where to insert your 
declarations and program code. Notice that the name of the program is the what you entered in the 
New Project... dialog. 

The project window contains three columns. The Options column lets you control some of the 
compiler options. You’ll see how these work later in this chapter. The File column shows you the 
name of each file. The Size column shows you the size of the code of each file and library in bytes. 

Note: The notation “by build order” means that the project window is showing 
you the files in the order they’ll be compiled. You’ll learn more about this in 
Chapter 5, “Tutorial: Hex Dump DA.”. 

THINK Pascal automatically inserts two standard libraries into your project, in addition to your 
source file. Runtime, lib contains the code for all the standard Pascal routines (like writeln). 
Interface . lib contains the glue code for all the Macintosh Toolbox routines marked [Not in 
ROM] . 


24 












































































Tutorial: Bullseye 


3 


You’ll use these two libraries in most of the programs you write. To learn more about libraries, read 
Chapter 10, “Units and Libraries,” and Chapter 11, “Using Predefined Routines.”. 

If you’re running under MultiFinder, you can go to the Finder and look at Bullseye f, the folder 
THINK Pascal created. It holds both Bullseye. p and Bullseye. n. 



25 





THINK Pascal User Manual 


Writing a Source File 

Now you’re ready to create your source file. Triple-click on the line { Insert your 
declarations here } to select it. Type in the declarations shown below (between the lines 
program Builseye and begin. 


Bullseye.p 


program Bullseye; 
const 
scale = 8; 

var 

hPos, vPos: integer; 

Radius , i: integer; 

begin 

{ Insert your program code here } 

end. 


SI 


KE 


Note: Make sure you type in the program exactly as it appears above. Remember, 
in Pascal punctuation is very important. 


26 






























































Now, triple-click on the line { Insert your program code here } and type the program 
shown below (between the first begin statement and the last end statement.) 



As you type, you’ll notice that the THINK Pascal editor formats (pretty-prints) your program for 
you. If you make a syntax error, the editor points it out by outlining the error text. In the example 
below, you forgot to type a comma between hPos and vPos: 



27 



























































































































THINK Pascal User Manual 


Aside from the special pretty-printing feature, the THINK Pascal editor works much like other text 
editors on the Macintosh. You can drag to select a range of text or double-click to select words. If 
you have a keyboard with arrow keys, you can use them to move around the file. To learn more 
about the THINK Pascal editor, see Chapter 6, “Editing.” 

Running the Program 

Now you’re ready to run your program. Choose Go from the Run menu. 

Because it’s an integrated environment, THINK Pascal knows that it needs to load the libraries and 
that it needs to compile your source file. You’ll see a dialog box that lets you know when THINK 
Pascal is loading or compiling. 


Compiling “Bullseye.p” 


0 lines 17 

Type 36-. to cancel the operation. 


When your program runs, it will open the drawing window and draw the bullseye design: 



28 




Tutorial: Bullseye 


3 


If you look at the project window now, you’ll see that the Size column now contains the sizes of 
the libraries and of your compiled code. 

Debugging the Program 

This program doesn’t have any bugs in it, so to debug it, you’ll have to introduce a bug. The bug 
will make THINK Pascal multiply two numbers so the result exceeds the legal range for integers. 

First, click on the project window to make it the active window. Next, click on the V and the R next 
to the bullseye. p entry. Now both letters should be outlined with a box: 


=n- = Bullseye. it ’■ 1U1=| 

Options File (by build order) Size 

& 

<> 

o 

Runtime.lib 17884 

Interface .lib 10106 

iDllNirvirRl Bullseye.p 160 

rofj/Coifc Sir* 28150 

oj_ia 

Q 


When you click on these two letters, you tell THINK Pascal to generate additional code to check for 
arithmetic overflow and for range checking. Range checking means that THINK Pascal checks to 
make sure that indices to arrays stay within in the bounds of the array, and that values assigned to 
subrange types stay within subrange. 


29 






THINK Pascal User Manual 


Now, change the program so the constant scale is equal to Max In t. Maxlnt is a built-in 
constant that’s equal to the largest allowed integer (32767). 


=l~l ; Bullseye.p 


program Bullseye; 
const 

scale = Maxlntj 

var 

hPos, vPos: integer; 
Radius, i: integer; 

begin 

ShowDr awing; 
hPos := 100; 
vPos := 100; 
PenMode(patXor); 

for i := 10 downto 1 do 
begin 

Radius := i * Scale; 
PaintCircle(hPos, yPos, 

end 

end. 





Radius) 



Make sure that the Confirm Saves option is on. This option checks whether you changed any of 
your source files before running your program. If it finds a file you changed, it asks you if you want 
to save them. Select the Run menu and see if there’s a checkmark beside Confirm Saves. If there 
isn’t, choose Confirm Saves. 

Now choose Go from the Run menu. THINK Pascal recompiles the program, and then displays this 
dialog box: 


Do you want to saue the changes to 
“Bullseye.p” before running? 


It Ves H 


No 


] [ Cancel ] 


THINK Pascal noticed that you had not saved the file. You can run the changed program without 
saving the file. In this case we know there’s a bug, so we don’t want to save the file. Click on the 
No button. 


30 







































































Tutorial: Bullseye 3 


Immediately after the program begins, you’ll see a bug dialog: 



THINK Pascal puts a “thumbs down” next to the offending line. In this case, it’s telling you that the 
multiplication i* Scale was out of the range for integers. 

To dismiss the bug box, click anywhere or press the Return or Enter key. 

The easiest way to undo the change you made to your file is to go back to the last saved version of 
the file. Choose the Revert command from the File menu. You’ll see this dialog box: 



Since you do want to go back to the last saved version, click on the OK button. You’ll be ready to 
learn how to use THINK Pascal’s debugging tools to step through your program. 


31 




THINK Pascal User Manual 


Stepping Through the Program 

THINK Pascal lets you step through your program one line at a time so you can watch what it’s do¬ 
ing. You can also watch the values that variables take on to make sure your program is behaving 
properly. 

First, make the edit window about half as wide as it is now so it doesn’t obscure the Drawing 
window. Next, choose Observe from the Debug menu. The Observe window appears. 

Type in the word Radius, then press Return. Type in the letter i, then press Return. These are the 
names of the variables you’ll be observing as you step through the program. 


,n 0bs 

Radius 

Di 

O 


i 

O 

Enter an expression 




iol 




Drag the Observe window so it’s above the Drawing window. It’s OK if it overlaps the project 
window. 


32 



















































































Tutorial: Bullseye 


3 


Now choose Step Into from the Run menu. THINK Pascal draws an execution finger next to the 
first line of your program. Keep choosing Step Into — better yet, use the Command-I equivalent 
—and watch what happens. The execution finger points to each line of the program. As you step, 
watch the values in the Observe window when the execution finger enters the loop. 


Obserue 

Bullseye. tt 



80 Radius 


Jptions File (by build order) Size 

£ 


10 i 

Interface .lib 10106 

EEH3E) Bu"“V» P..1.60 

Enter an expression 

EL 


totj/C** Sv* 28150 


Bullseye. p | 


□ 


program Bullseye; 
const 
scale * 8; 
var 

hPos, vPos: integer; 

Radius,i:integer; 

begin 

ShovDr awing; 
hPos := 1 00; 
vPos := 100; 

PenMode(patXor); 

for i :* 10 downto 1 do 
begin 

Radius := i * Scale; 

PaintCircle(hPos, vPos, Radius) 

& end 

end. 

<> 

2 


a 

01 .K> 



Every time your program stops, THINK Pascal updates the values in the Observe window. 

If you get tired of stepping, THINK Pascal can step automatically for you. Hold down the Option 
key and select the Run menu. The Step Into command is now the Step-Step command. Choose it. 
When you use this command, THINK Pascal runs your program in slow motion, as if you kept on 
choosing Step Into yourself. To pause your program, click on the Bug Spray icon in the upper- 
right hand corner. To start it up from where you paused, choose Step-Step again. 


Where to Go Next 

The tutorial in the next chapter is a more elaborate example. It shows you how to build a double- 
clickable Macintosh application, and some of the more advanced features of THINK Pascal. 

If you would rather explore on your own, read the chapters of the “Using THINK Pascal” section 
that interest you. They’re designed to be read in order, but you can skip around if you like. 


33 







Tutorial: ObjectDraw 

4 


Introduction 

This tutorial shows you how to put together a Macintosh application in THINK Pascal. The applica¬ 
tion you’ll build is called ObjectDraw. It’s a simple drawing program that lets you draw several 
kinds of shapes in a window. ObjectDraw lets you print the window to any printer, and it lets you 
save your picture as a PICT format file that you can edit with drawing programs. It can also display 
any file saved in the PICT format, but it doesn’t let you edit the picture. 

ObjectDraw shows you how to use resource files with your THINK Pascal programs and how to 
add some of the special libraries to your project. 

ObjectDraw uses Object Pascal, but this tutorial won’t show you how to use Object Pascal. For 
more information, see the Object-Oriented Programming Manual , especially Chapter 4, “Object 
Pascal,” and Chapter 5, “Tutorial: LearnOOP.” 

Note: The pictures for this tutorial were made under System 6. The tutorial works 
under System 7, but some dialog boxes will look slightly different from those in 
the pictures. 

Before you begin 

Make sure that you followed the instructions in Chapter 2, “Installing THINK Pascal,” for installing 
THINK Pascal on your Macintosh. For this tutorial, you need to make sure these files and folders 
are installed: 

• The Libraries and Interfaces folders in the THINK Pascal 4.0 Folder. 

They’re from the Interfaces & Libs . sea archive 

• The ObjectDraw f folder in the THINK Pascal 4.0 Demos folder. This folder 
contains all the source files and resource files that you’ll use in this tutorial. It’s from the 
THINK Pascal 4.0 Demos . sea archive. 

Topics covered In this chapter 

• Creating the project 

• Adding the libraries 

• Adding the source files 

• Setting the Run Options 

• Setting the Compile Options 

• Running the project 

• Building the application 

• Where to go next 



THINK Pascal User Manual 


Creating the Project 

Since the Ob jectDraw f folder is already on your disk, you don’t need to create a new folder for 
the ObjectDraw project. But you do need to remove the project file, named Ob jectDraw. n, that’s 
in ObjectDraw f. That project lets you use ObjectDraw without completing this tutorial. Move it 
to another folder or back it up to another disk. 

All you need to do now is double-click on the THINK Pascal icon. THINK Pascal displays this 
dialog when you launch it from the Finder. 


QTHINK Pascal Folder] 



You’re creating a new project, so click on the New button. 

THINK Pascal displays a standard file dialog that lets you create projects. 
Move to ObjectDraw f in the THINK Pascal 4.0 Demos folder.. 

Note: It’s very important to move to the ObjectDraw f folder. 


36 






Tutorial: Object Draw 


Make sure the Instant Project option is off. Name the new project Ob jectDraw. n, and click on 
the Create button. (To make a u n” hold down the Option key as you press the letter “p”. By 
convention, all THINK Pascal projects end in .tc.) 


Sl ObjectDraui f | 



D BialogUIMs.p C 

D ErobetiOefProe.p 

Q (Jhj<« tOraui.p 

D tOraui.Rsr* 

D OBCoent.p 

D SO I nil.p <; 

3 oflkbar 

3 i : 

[ Driue 

i 

Create the project: 

|[ Create | 


ObjectDraui .tt 

~\ [ Cancel 

□ Instant Project 



Note: To learn more about the Instant Project option, see Chapter 3, “Tutorial: 
Bullseye.” 

THINK Pascal creates a new project document on the disk and displays a project window. Your 
project window should look like this: 


=n = ObjectDram.TT ==^- : P~1=| 

Options File (by build order) Size 

& 

<> 

Runtime .lib 0 

Interface .lib 0 

Tote? Coifc Sin? 0 

5i id 

Q 


Next, you’ll add the libraries to your project, and then you’ll add the source files. 

Adding the Libraries 

THINK Pascal automatically inserts the names of two standard libraries into your project. 
Runtime . lib contains the code for all the standard Pascal routines (like writeln). 











THINK Pascal User Manual 


Interface. lib contains the glue code for all the Macintosh Toolbox routines marked [Not in 
ROM] . 

ObjectDraw is a true Macintosh application, so it doesn’t use any of the Pascal input/output rou¬ 
tines in Runtime. lib. If you leave the Runtime. lib library in your project, your program will 
run perfectly, but there will be code in your project that ObjectDraw never uses, and your project 
file will be bigger than it really needs to be. But ObjectDraw still needs some of the routines in 
Runtime . lib. Even if a program doesn’t explicitly call any of the routines in it, it contains code to 
handle 32-bit multiplication, set operations, and other things that your program may need. 

THINK Pascal has a smaller version of Runtime. lib called pRuntime . lib which doesn’t in¬ 
clude the Pascal standard input/output code. To replace Runtime. lib with pRuntime. lib, 
hold down the Option key as you double-click on Runtime. lib in the project window. THINK 
Pascal displays this dialog: 


*Sl ObjectDrau) j | 


CD Sample Pictures 

O 

<=> Rkbar 



*)«<* ) 



[ Driue ] 



([ rhaiuje to ]| 


O 

[ Cancel ] 






Tutorial: Object Draw 


(iRuntime . lib is in the Libraries folder, so move to that folder, select (iRuntime. lib, and 
click on the Change To button. 


Q Libraries! 



a 

<=> Rkbar 

□ RBPackage.lib 

□ DRURRuntime.lib 

□ FinMath.lib 

□ Graf3D.lib 

□ HyperHLib.lib 


f £ 1 0< 1 ' 

[ Driue ] 

□ nfippleTalk.lib 

□ PrintCaMs.lib 

□ SRNELib.lib < 

i 

[ Change to J| 

> 

[ Cancel 


When you use (IRuntime .lib, you can’t use the THINK Pascal input/output routines like reset, 
rewrite, writeln, readln, etc. If you plan to write Macintosh applications exclusively, it’s a 
good idea to use (IRuntime .lib instead of Runtime. lib to make your projects smaller. 

Note: Whether you use Runtime . lib or (IRuntime. lib, your finished appli¬ 
cation will be the same size because THINK Pascal uses smart linking to remove 
references to unused code in your final application. The difference is only in the 
project size. 












THINK Pascal User Manual 


Adding the Source Files 

Now you’ll add the source files to your project. Hold the Option key and select the Add Files... 
command from the Projects menu. To see the command, hold down the Option key as you select 
the Project menu. You see this dialog: 


Q Libraries | 


D RBPatkage.lib 


□ DRURRuntime.lib 

□ FinMath.lib 

□ Graf3D.lib 

□ HyperKLib.lib 

□ nflppleTalk.lib 

□ PrintCalls.lib 

□ SRNELib.lib 


» ii 

Add fill ) 

[ Remote 





<—> Rkbar 

i m 

c 


Driue 


b<jh« 


3 


[ Cancel ] 


The top list displays the contents of the folder you’re currently in. The bottom list shows the files 
THINK Pascal will add to your project. 

The first source file you’ll add is Print Traps . p, the interface for the Print Manager described in 
Inside Macintosh IV. Move to the Interfaces folder. To add PrintTraps . p, either select it 
and click on the Add button, or double-click on it. Notice that PrintTraps . p disappears from 
the top list and appears in the bottom list. 

Note: If you accidentally add the wrong file to the bottom list, select it and click 
on Remove. Then add the correct file. 













Tutorial: Object Draw 


Your dialog should look like this: 


QInterfaces! 



g <=> Rkbar 

□ QuickDraw32Bit.p 


□ Resources.p 

[ ] 

□ Retrace.p 

f Driue ] 

D ROMDefs.p 


D SRNE.p | 

Done 1 

□ Scrap.p 

k J 

□ Script.p < 

> Cancel ] 



__ 


PrintTraps.p 

O 

li "dd J 



Add Rll ] 


s 

[ Remote ] 


The next two files you need to add are in here, too. Add the file Script. p by selecting it and 
clicking on Add or by double-clicking on it. It’s the interface for the Script Manager, in Inside 
Macintosh V ObjectDraw doesn’t use the Script Manager, but the interface file defines the function 
GetMBarHeight which ObjectDraw uses to figure out where to position its windows. 

Finally, add Ob jlntf. p. It contains the most primitive object class, TOb ject. 

Note: You don’t have to add Ob j Int f. p to your project to use Object Pascal. 

You do need it if you define your objects in terms of TOb ject like ObjectDraw 
does. 


















THINK Pascal User Manual 


Now move back to Ob jectDraw f. The rest of the source files are in this folder. Add the source 
files in this order: 

• DialogUtils.p 

• EmbedDefProc.p 

• PrintDialogs.p 

• ODIntf.p 

• ODMDefs.p 

• ODMenu.p 

• ODTList.p 

• ODTWindow.p 

• ODTDrawWindow.p 

• ODTPicWindow.p 

• ODTShape.p 

• ODEvent.p 

• ODInit.p 

• ObjectDraw.p 

You finished adding all the files you need to your project, so click Done. Your project window 
should now look like this: 


Options 

ObjectDraw.TT 1 
File (by build order) 

Size 

31 

A 





URuntime.lib 

0 

■{> 





Interface .lib 

0 



0 

N 

V 

R 

PrintTraps.p 

0 



0 

0 

V 

R 

Script .p 

0 



0 

0 

V 

R 

Objlntf.p 

0 



0 

0 

V 

R 

DialogUtils .p 

0 



0 

0 

V 

R 

EmbedDefProc.p 

0 



sm 

V 

R 

PrintDialogs.p 

0 



DlN 

V 

R 

ODIntf.p 

0 



01 

V 

R 

ODMDefs.p 

0 



0FT 

V 

R 

ODMenu .p 

0 




E 

V 

R 

ODTList .p 

0 



dTn 

V 

R 

ODTWindow.p 

0 



D 

E 

V 

R 

ODTDraw Window .p 

0 



D 

1 

V 

R 

ODTPicWindow .p 

0 



D 

1 

V 

R 

ODTShape.p 

0 



D 

1 

V 

R 

ODEvent.p 

0 



D 

1 

V 

R 

ODInit.p 

0 



D 

E 

V 

R 

ObjectDraw.p 

0 






fotef Sir* 

o 

O' 

21 






_l£ 

lol 


42 







Tutorial: Object Draw 


If you discover that you’ve made a mistake in the order that you add the files, don’t worry. After 
you’ve added all the files to the project, just click on a file name and drag it to the proper position. 
To learn more about arranging files in projects, see Chapter 7, “Working with Projects.” 

Note; Files have to appear in the project in a particular order because Pascal 
requires that you define something before you use it. 


This is what’s in each of the files. You might want to print them out to study them, but for this 
tutorial that’s not necessary. 


File 

DialogUtils.p 
EmbedDefProc.p 

PrintDialogs.p 
ODIntf.p 
ODMDefs.p 

ODMenu.p 
ODTList.p 

ODTWindow.p 


ODTDrawWindow.p 
ODTPicWindow.p 

ODTShape.p 
ODEvent.p 

ODInit. p 
ObjectDraw.p 


Description 

Useful utilities for dialog boxes 

A routine to let a program use definition routines (like an MDEF) 
that are in a program’s source, and not in a separate resource. 
Routines to handle the customized print dialogs. 

The basic types, constants, and variables that ObjectDraw uses. 
The MDEF resources for the special pallet-like Tool, Color, and 
Pattern menus. 

Routines to handle menu and Command-key commands. 

The class TList, a linear list of objects, used for the list of shapes 
in an ObjectDraw window. 

The class TWindow. ObjectDraw never creates an instance of this 
class, but both TDrawWindow and TPicWindow inherit it. It 
defines behavior common to both classes of windows. 

The class TDrawWindow, an ObjectDraw window you draw in. 
The class TPicWindow, an ObjectDraw window that displays a 
picture. 

Classes for all the kinds of shapes you can draw. 

The event loop for ObjectDraw and routines to handle most 
Macintosh events, like mouse, window, and key events. 

The initialization routines for ObjectDraw. 

The main program for ObjectDraw. 




THINK Pascal User Manual 


Setting the Run Options 

Before you run the project, you must let the project know where its resources are. The resources 
contain the contents of the menus, text used in the About... box, and more. Choose the Run 
Options... command in the Run menu. You’ll see this dialog box. Click on the Use Resource File: 
check box. 


Run-time Enuironment Settings 


□ Use resource file: 

Resources - 

for resources used by the project. 


Tent Window saues 


5000 


characters 


TeKt 

LUindoiu 


□ Echo to the printer 

□ Echo to the file:! 


He Ilo world, x = 811.79. 


Monaco 


3CHZI 


Memory 


Stack size: ||^J] kilobytes 
Zone size: |256 [ kilobytes 


i» E i 


! c 


Cancel 


44 







Tutorial: Object Draw 


You’ll see a standard file dialog. Select Ob jectDraw. Rsrc and click on the Use button. Then, 
click on the OK button in the Run Options... dialog. 




O ObjectDraw f | 






5 

c=> Rkbar 



CD Sample Pictures 







[ 1: j«< t 

J 




[ Driue 

J 




| Open 

i 



2 

[ Cancel 

D 

1 

__ 




Memory 


Stack size:| 16 |kilobytes 

l( ° K 1 

Zone size:|256 |kilobytes 

j Cancel ] 


When you run ObjectDraw in the THINK Pascal environment, THINK Pascal will open this file to 
find ObjectDraw’s resources. And when you build the ObjectDraw application, THINK Pascal will 
place the resources in this file into the application. 

The resource file ObjectDraw. Rsrc was created with ResEdit. You can use ResEdit to look at or 
change some of the resources. 

NOTE: A RESOURCE FILE USED BY A PROJECT MUST BE IN THE SAME FOLDER AS 
THE PROJECT. 








THINK Pascal User Manual 


Setting the Compile Options 

This project takes advantage of a THINK Pascal extension to the Pascal language, called the ‘USES’ 
Extensions. This option lets you shorten the uses clause in your files. 

To take advantage of this opition, you have to turn it on. Choose Compile Options... from the 
Project menu. Click on the ‘USES’ Extensions box. The dialog should look like this: 


Compiler Uariables: 


THINK_PascaI = TRUE; 

THINK_PascaI _Uersion_4 = TRUE; 
EIems881 = TRUE; 


o 


o 


0 ‘USES’ EHtensions 


» BK I 

[ Cancel ] 


Code Generation: 

□ 68020/68030 □ Large Sets 

□ 68881/68882 □ Long Names 

□ Profile 


Now, click on OK. 

Note: You don’t have to understand the ‘USES’ Extensions option to finish this 
tutorial. The following explanation gives you an idea of what the option does. If 
you want more information, see Chapter 10, “Units and Libraries.” 


46 






Tutorial: Object Draw 


The ‘USES’ Extensions option lets you use propogated uses. If your unit uses other units, any unit 
that uses your unit also uses those units automatically. Say, you have three units A, B, and C. Unit A 
includes unit B in its uses clause, and unit C includes unit B in its uses clause, but unit C doesn’t 
include unit A. If you use the ‘USES’ Extensions, THINK Pascal assumes that unit C uses unit A, 
even though unit A doesn’t appear in unit C’s uses clause. If you don’t use the ‘USES Extensions, 
THINK Pascal assumes unit C doesn’t use unit A. 

Running the Project 

Now you’re ready to run the project. Choose Go from the Run menu. THINK Pascal loads all the 
libraries and compiles all the source files. When it finishes compiling, THINK Pascal launches the 
ObjectDraw application. 



If you like, you can click on the bug spray can in the far right of the menu bar to halt the program 
so you can use THINK Pascal’s debugging tools. The debugging tools are described in Chapter 9, 
“Debugging Programs, and Chapter 14, “LightsBug.” 

Building the Application 

Once you’re sure that the ObjectDraw application runs correctly, you can build it as a double-click¬ 
able application. First, you need to give the application a signature, so the Finder knows how to 
display its icon. 


47 


























































































































































































THINK Pascal User Manual 


Choose Set Project Type... in the Project menu. Set the creator to RS$$ and make sure that the 
Bundle Bit check box is checked. Click on the OK button to continue. 



Note: If you don’t set the creator to RS$$, the Finder won’t display ObjectDraw’s 
icon. RS $ $ are the initials of the developer who wrote ObjectDraw (Rich Siegel). 
The $ $ is there because he’s Rich. 


The Finder uses the signature, the BNDL, FREF, ICN#, and RS$$ resources in ObjectDraw’s re¬ 
source file to give an application an icon. Inside Macintosh III, Chapter 1, “The Finder Interface”, 
and Inside Macintosh VI, Chapter 9, “The Finder Interface,” describes the mechanism in detail. 


48 







































Tutorial: Object Draw 


You’re finally ready to build the application. Choose Build Application... from the Project menu 
You’ll see a dialog box asking you to name the application. Name the application ObjectDraw. 


ObjectDraw f | 



Q DtaiogUltK.p £ 

>] <=>Rkbar 


Q EmbetiOefProe.p 

„ f — zr~. -:-N 


Q Ob tOraw.ir 

[ 1 


Q Ob }e< MJnsw.p 

[ Driue ] 


Q Ob je< tOraw.Rsrc 



Q ODEuentp t 

1 

Saue Rpplication as 

. Lssissjl 


ObjectDraw 

| [ Cancel ~) 

^ Smart Link 


When the Smart Link check box is checked, THINK Pascal strips out any code the application 
doesn’t use so that the final application is as small as possible. 

After THINK Pascal finishes building your application, quit to the Finder, and look in the 
ObjectDraw folder. There you’ll see your new application’s icon. 



ObjectDraw 

Double-click on it to make sure it works. Congratulations! You’ve built a real Macintosh 
application. 


Where to Go Next 

The next chapter shows you how to build a desk accessory. If you want to keep playing with 
ObjectDraw, read Chapter 9, “Debugging Programs, and Chapter 14, “LightsBug,” to learn how to 
use THINK Pascal’s debugging tools. If you want to start creating your own programs, skip to the 
“Using THINK Pascal” section. And if you want to learn more about Object Pascal, which is used 
throughout ObjectDraw, see the Object-Oriented Programming Manual , Chapter 4, “Object 
Pascal,” and Chapter 5, “Tutorial: LearnOOP.” 













Tutorial: Hex Dump DA 

5 


Introduction 

This tutorial shows you how to test and build a desk accessory in THINK Pascal. The desk acces¬ 
sory is Hex Dump, a utility that displays the contents of a file in hexadecimal and ASCII. Some of 
the instructions in this tutorial are the same as for building an application, so you’ll be familiar with 
the process. This tutorial takes you step by step, so if you didn’t build ObjectDraw, you’ll still be 
able to create Hex Dump. You might want to take a glance over at the previous chapter before you 
begin, though. 

Building a desk accessory is a little more difficult than building an application, and this tutorial will 
introduce you to some new concepts and commands fairly quickly. You may want to skim the 
tutorial first before you start just to make sure you’re ready. 

Before you begin 

Make sure that you followed the instructions in Chapter 2, “Installing THINK Pascal,” for installing 
THINK Pascal on your Macintosh. For this tutorial, you need to make sure these files and folders 
are installed: 

• The Libraries folder. It’s from the Interfaces & Libs . sea archive 

• The Interfaces folder. It’s from the Interfaces & Libs . sea archive 

• The DA Shell file in the THINK Pascal 4.0 Folder. It’s from the Interfaces & 
Libs. sea archive. 

• The Hex Dump Folder in the THINK Pascal 4 . 0 Demos folder. This folder 
contains all the source files and resource files that you’ll use in this tutorial. It’s from the 
THINK Pascal 4 . 0 Demos . sea archive. 

Note: The pictures for this tutorial were made under System 6. The tutorial works 
under System 7.0, but some dialog boxes will look slightly different from those in 
the pictures. 

Topics covered in this chapter 

• Writing desk accessories 

• Creating the project 

• Changing a library 

• Adding the source files 

• Setting the Compile Options 

• Setting the Run Options 

• Segmenting the project 

• Building the desk accessory 

• Where to go next 



THINK Pascal User Manual 


Writing Desk Accessories 

Desk accessories and applications are structurally quite different. A desk accessory is a small pro¬ 
gram that runs as the “guest” of an application. Of you’re using MultiFinder, the DA Handler is the 
“host” program.) While applications get their events from the Toolbox’s Event Manager, desk ac¬ 
cessories get their events directly from the system. Desk accessories need to be able to respond to 
certain conditions — the host application quitting, for instance — that don’t apply to applications. 

To debug a desk accessory, you have to fool THINK Pascal into thinking that the desk accessory is 
actually an application. The DA Shell, included in your THINK Pascal package, is designed to pro¬ 
vide an environment that looks like an application to THINK Pascal and that looks like a host 
application to your desk accessory. 

In this tutorial, you’ll learn how to use the DA Shell to debug your desk accessories. The main point 
to remember is that you test your desk accessory in one environment and you build it in another. It 
may sound hard at first, but it’s really not. All it takes is a couple of extra steps. 

Creating the Project 

Since you’ve already copied the Hex Dump Folder to your disk, you don’t need to create a new 
folder for the Hex Dump project. But you do need to remove the project file, named Hex Dump. n, 
that’s in the Hex Dump Folder. That project lets you use Hex Dump without completing this 
tutorial. Move it to another folder or back it up to another disk. 

Double-click on the THINK Pascal icon to launch THINK Pascal. THINK Pascal displays this dialog 
when you launch it from the Finder. 


f 



{=3THINK Pascal Folder 


CD Interfaces 

CD Libraries 

CD THINK Class Library 

O 

O 


<=>Rkbar 


i mu i 



52 






Tutorial: Hex Dump DA 


5 


You’re creating a new project, so click on the New... button. 

THINK Pascal displays a standard file dialog that lets you create projects. 

Move to the Hex Dump Folder that you copied from your THINK Pascal disk. 

Note: It’s very important to move to the Hex Dump Folder. 

Name the new project HexDump. n. Make sure the Instant Project option is off, and click on the 
Create button. (To make a “7t” hold down the Option key as you press the letter “p”. By 
convention, all THINK Pascal projects end in .7t.) 





S) Hen Dump Folder| 


Q durnp.p C 

D fHevp 

Q I'sml.p 

Q globaU.p 

Q <)«1<s,p 

D HeKtlurnp. n.rsrt < 

>• <=>flkbar 

rw 

l Driue j 

i 

Create the project: Create j| 


HeHDump.tr 

| Cancel ] | 

□ Instant Project 


Note: To learn more about the Instant Project option, see Chapter 3, “Tutorial: 
Bullseye.” 

THINK Pascal creates a new project document on the disk and displays a project window. Your 
project window should look like this: 


Options 

m HenDump.Tf == 
File (by build order) 

Size 

31 

|4 


Runtime.lib 

Interface .lib 

0 

0 

o 


Sire 

o 

o 

0 


it> 

Q 


53 











THINK Pascal User Manual 


Next, you’ll change a library in your project, and then you’ll add the source files. 


Changing a Library 

THINK Pascal automatically inserts the names of two standard libraries into your project. 
Runtime .lib contains the code for all the standard Pascal routines Oike writeln). 
Interface, lib contains the glue code for all the Macintosh Toolbox routines that Inside 
Macintosh marks [Not in ROM]. 


If you went through the tutorial in the last chapter, you remember that it’s better to use the 
^Runtime. lib library when you’re writing real Macintosh applications — that is, applications 
that don’t use any Pascal standard input/output routines. Well, the fact of the matter is that you 
can’t use the Pascal input/output routines in desk accessories anyway. 


When you’re writing desk accessories, you use another library called DRVRRuntime. lib. This li¬ 
brary is designed specifically for programs that are not applications: desk accessories, device 
drivers, and code resources. The difference between jiRuntime. lib and DRVRRuntime. lib is 
that DRVRRuntime. lib uses register A4 instead of register A5 to access global variables. 

Note: You don’t have to know what this means to write desk accessories, but if 
you’re interested, look at Chapter 12, “Building Projects.” 


When you’re testing your desk accessory with the DA Shell (which you’re about to do), you use 
^Runtime. lib. After you’ve tested your desk accessory, and it’s time to build it, you use 
DRVRRuntime . lib. This sounds more difficult than it is. Here’s a chart that makes things clearer: 


When you’re... 

Building an application that uses standard Pascal 
input/output 

Building a Macintosh application that doesn’t use 
Pascal input/output 

Testing a desk accessory with the DA Shell 
Building a desk accessory 
Building a code resource 


You use... 

Runtime. lib (the default) 

jiRuntime .lib 

jiRuntime.lib 
DRVRRuntime.lib 
RSRCRuntim.lib 



If you’re still not clear about all this library stuff, don’t worry. This tutorial takes you step by step. 


To replace Runtime .lib with jiRuntime. lib, hold down the Option key as you double-click 
on Runtime. lib in the project window. THINK Pascal displays this dialog: 


Sl Hex Dump Folder 


Rkbar 


Lhonue to 


Cancel 


^Runtime. lib is in the Libraries folder, so move to that folder, select ^.Runtime. lib, and 
click on the Change To button. 


€3 Libraries 


^.Runtime.lib 


□ RBPackage.lib 

□ DRURRuntime.lib 

□ FixMath.lib 

□ Graf3D.lib 

□ HyperHLib.lib 

□ nRppleTalk.lib 

□ PrintCalls.lib 

□ SANELib.lib 


Rkbar 


Change to 


Cance 














































THINK Pascal User Manual 


Adding the Source Files 

Now you’ll add the source files to your project. Hold down the Option key and select the Add 
Files... command from the Projects menu. To see the command, hold down the Option key as 
you select the Project menu. You see this dialog: 


€3 Libraries 




□ DRlIRRuntime.lib 

□ FiHMath.lib 

□ Graf3D.lib 

□ HyperKLib.lib 

□ nflppleTalk.lib 

□ PrintCalls.lib 

□ SRNELib.lib 

<> 


<=)Rkbar 




& 




11 Add j| 



[ Rdd Rll ] 


s 

f 


The top list displays the contents of the folder you’re currently in. The bottom list shows the files 
THINK Pascal will add to your project. 

The first source file you’ll add is globals . p. Go to the Hex Dump Folder. To add 
globals. p, either select it and click on the Add button, or double-click on it. Notice that 
globals . p disappears from the top list and appears in the bottom list. 

Note: If you accidentally add the wrong file to the bottom list, select it and click 
on Remove. Then add the correct file. 


56 













Tutorial: Hex Dump DA 


5 


Your dialog should look like this: 


Q Hen Dump Folder 


□ dump.p 

□ files.p 

□ find.p 


□ goto.p 


□ lines.p 

□ main.p 

□ selection.p 

□ utilities.p 


Rkbar 


Cancel 


globals 


Hdd an 


Rernoue 


Now add the rest of the source files in this order: 

• utilities.p 

• lines.p 

• windows.p 

• files.p 

• selection.p 

• goto.p 

• find.p 

• dump .p 

• main.p 

Since you’ll be testing the desk accessory before you actually build it, you need to add the DA Shell 
to your project. This source file is in the same folder as THINK Pascal. If you followed the installa¬ 
tion instructions, that folder is THINK Pascal 4.0 Folder. Move to that folder and add the 
file DA Shell. 




































THINK Pascal User Manual 


You finished adding all the files you need to your project, so click Done. Your project window 
should now look like this: 


HeKDump.'if 


Options File (bu build order) Size 


pRuntime.lib 
Interface .lib 


fotefCoifc Ski* 


D 

N 

V R globals.p 

0 

D 

N 

V R utilities .p 

0 

D 

N 

V R lines .p 

0 

D 

N 

V R windows .p 

0 

D 

N 

V R files .p 

0 

D 

N 

V R selection .p 

0 

D 

N 

V R goto.p 

0 

D 

N 

V R find.p 

0 

D 

N 

V R dump.p 

0 

D 

N 

V R main.p 

0 

D 

N 

V R DA Shell 

0 


A 

5 


& 


Q 


If you discover that you’ve made a mistake in the order that you add the files, don’t worry. After 
you’ve added all the files to the project, just click on a file name and drag it to the proper position. 
To learn more about arranging files in projects, see Chapter 7, “Working with Projects.” 

Note: Files have to appear in the project in a particular order because Pascal 
requires that you define a procedure or function before you can use it. 






Tutorial: Hex Dump DA 


5 


Here is a description of what each of the files does. You might want to print them out to study 
them, but for this tutorial that’s not necessary. 


File 

globals.p 
utilities.p 
lines.p 
windows.p 
files.p 
selection.p 

goto.p 

find.p 
dump. p 

main.p 


Description 

All the global variables for the project. 

Some utility routines used in the project 

Fills a string with a line of the Hex Dump display. 

Handles Hex Dump’s window. 

Opens, closes, and reads the displayed file. 

Highlights selected data from the displayed file (used by goto. p and 
f ind. p). 

Lets the user go to a position in the file, and displays the data at that 
position. 

Lets the user enter an ASCII or hexadecimal string, and finds it. 

Dumps the hexadecimal and ASCII representation of the displayed file 
to a text file. 

Defines a function main that THINK Pascal uses as the entry point of 
the desk accessory. See Chapter 12, “Building Projects,” for details. 


Setting the Compile Options 

THINK Pascal lets you use a desk accessory two ways: you can run it under the DA Shell to test it 
or you can build a “suitcase” file when it’s finished. However, when you build the suitcase file, you 
need to include some code that you don’t need when you run under the DAShell. Hex Dump uses 
conditional compilation so you can use the same source files in either case. You’ll define a 
compiler variable called DAShell to let THINK Pascal know which code to compile. 

For example, this procedure will set up and restore the A4 register only when you’re building a 
suitcase file: 

procedure ScrollProc(theControl: ControlHandle; theCode: integer); 

begin 

{$IFC NOT DAShell} 

SetUpA4; 

{$ENDC} 

if theCode = scrollCode then 

{$IFC NOT DAShell} 

RestoreA4 ; 

{$ENDC} 

end; 


Note: For more information on compiler variables, see “Using Conditional 
Compilation” in Chapter 15. For more details on writing desk accessories in 
THINK Pascal, see “Building Desk Accessories and Device Drivers” in Chapter 12. 


59 



THINK Pascal User Manual 


THINK Pascal lets you define compiler variables with the Compile Options... command. Choose 
Compile Options... from the Project menu. You’ll see this dialog: 


Compiler Uariables: 

If OK | 

THINK_Pascal = TRUE; 

TH1NK_Pasca1_Uersion_4 = TRUE; 

E1ems881 = TRUE; 



o 

[ Cancel ] 



□ ‘USES’ Extensions 


Code Generation: 

□ 68020/68030 □ Large Sets 

□ 68881/68882 □ Long Names 

□ Profile 


THINK Pascal defines three symbols for you. THINK_PASCAL is always defined as true. You can 
use this symbol if you need to know whether your program is being compiled in THINK Pascal. 
THINK_Pascal_Version_4 is always true, too. Use this symbol if you need to know whether 
your program is being compiled by the latest version of THINK Pascal. The symbol Elems881 is 
used to generate code for the MC68881 math coprocessor. See Chapter 15, “Compile Directives,” to 
learn more. 


60 






Tutorial: Hex Dump DA 


5 


To run HexDump under the DAShell, define the compiler variable DAShell to be true. Type 
DAShell=TRUE; into the dialog and click on the OK button: 


Compiler Uariables: 


THINK_PascaI = TRUE; 

THINK_PascaI_Uersion_4 = TRUE; 
EIems881 = TRUE; 

DRShelI = TRUE; 


□ ‘USES’ Extensions 


Code Generation: 

□ 68020/68030 

□ 68881/68882 

□ Profile 


□ Large Sets 

□ Long Names 


Cance 


Later on, when you build the desk accessory, you’ll set DAShell to FALSE. 

Note: There’s nothing magic about this compiler variable. You don’t have to write 
your desk accessories this way if you don’t want to. 













THINK Pascal User Manual 


Setting the Run Options 

Now you have to make sure that the project knows where its resources are. Choose the Run 
Options... command in the Run menu. You’ll see this dialog box. Click on the Use resource file 
check box. 


Run-time Enuironment Settings 


Resources 


* 


Use resource file: 

for resources used by the project. 


Text 

UJindoLU 


Text Window saues 


5000 


characters 


□ Echo to the printer 

□ Echo to the file:! 


He Ilo world, x * 811.79. 


Monaco 


9 ▼ 


Memory 


Stack size: |E3B| kilobytes 
Zone size: [ 256 | kilobytes 


» ° k i 

[ Cancel 








Tutorial: Hex Dump DA 


5 


You'll see a standard file dialog. Select HexDump.rc. rsrc and click on the Use button. Then, click 
on the OK button in the Run Options... dialog. 


<=9 Hen Dump Folder | 




I 1 D He« Dump 

K> 

onkbar 










i 

□ 




[ Driue 

□ 








|[ Open jl 



2 

[ Cancel 

□ 

1 

__ 




Memory 


Stack size:[ 16 |kilobytes 

1 1 0K Jl 

Zone size:| 128 jkilobytes 

: 

: 

[ Cancel ] 


The resource file HexDump .n. rsrc was created with ResEdit. You can use ResEdit to look at or 
change some of the resources. 

NOTE: A RESOURCE FILE USED BY A PROJECT MUST BE IN THE SAME FOLDER AS 
THE PROJECT. 

Segmenting the Project 

To make sure that Hex Dump will work well when memory is low, you’ll split it into two segments, 
moving some infrequently used code to a new segment. Macintosh programs are made up of one 
or more segments that contain the machine language code of your program. The Macintosh operat¬ 
ing system takes care of loading these segments when you need them. If you don’t use any code in 
a segment while using a desk accessory or application, that segment will not be loaded. Although 
it’s a good idea to split your program into a few small segments, the only time you must segment 
your program is when it is over 32K. When THINK Pascal discovers that a segment is larger than 
32K, you must break up your program into more segments. 


63 








THINK Pascal User Manual 


Click on the “Towers of Hanoi” icon (£3) just above the up-arrow o n the right of your project 
window. The project window changes, and it looks like this: 



64 





Tutorial: Hex Dump DA 


5 


Click on the last file in the project, DA Shell, and drag it below the line labeled Main. Your project 
window should now look like this: 



Now your program has two segments. Move these files into the new segment with DA Shell: 

• selection.p 

• goto.p 

• find.p 

• dump.p 


65 







THINK Pascal User Manual 


Your project window should look like this: 




Options 


[DpIV R 
[D][N] V R 
EHHIV R 
[D](NlV R 
[D][N]V R 
IMFil V R 


IdIInI v" 

[D ] [N ] V 

IHHlv 

[d][n] V 

mm v 


R 

R 

R 

R 

R 


5T 


File (by segment) 
pRuntime.lib 
Interface .lib 
globals.p 
utilities .p 
lines .p 
windows .p 
files .p 
main.p 

«S5_MethTables» 

«^_SelProcs» 

AOot 

selection .p 
goto.p 
find.p 
dump .p 
DA Shell 


Size 


RS 


& 




Click in the icon in the upper right corner of the window again to go back to the original view of 
your project. 

The normal view you’re used to by now is called the Build Order view because it lists the files in 
the order that THINK Pascal compiles them. The other view is called the Segment view because it 
shows how your program is broken up into different segments. 

Note: To learn more about segmentation, see Chapter 7, “Working with Projects.” 


66 







Tutorial: Hex Dump DA 


5 


Running the Project 

Now you’re ready to run the project. Choose Go from the Run menu. THINK Pascal loads all the 
libraries and compiles all the source files. When it finishes compiling, THINK Pascal launches the 
DA Shell. To use your desk accessory, choose the Sample DA command from the Apple menu. 
The DA Shell starts your program and feeds it events so it looks like it’s a desk accessory. 

Hex Dump will ask you to choose a file. After you choose one, you’ll see a Hex Dump window, 
like this one: 


IDfiS! 

EOF = 

12968 

<$32R8> 


= main.p 

rr— 

sags! 

Data fork 

IE 

Di 

[5 

000000 

7B20 

0960 

6169 

6E2E 

4865 

7844 

7560 

7044 

{..main.HexDumpD 



000010 

412E 

7070 

0D7B 

2020 

2020 

7000 

7B20 

0948 

fi.p). H 



000020 

6578 

4475 

6070 

2069 

7320 

6120 

4441 

2074 

exDump.is.a.DR.t 


000030 

6861 

7420 

6469 

7370 

6C61 

7973 

2074 

6865 

hat.displays.the 



000040 

2063 

6F6E 

7465 

6E74 

7320 

6F66 

2061 

2066 

.contents.of.a.f 



000050 

696C 

6520 

696E 

2068 

6578 

2061 

6E64 

2041 

i1e.in.hex.and.R 



000060 

5343 

4949 

2C09 

0970 

0D7B 

2009 

696E 

7465 

SCI 1.inte 



000070 

6E64 

6564 

2061 

7320 

616E 

2065 

7861 

6070 

nded.as.an.examp 



000080 

6C65 

206F 

6620 

686F 

7720 

746F 

2077 

7269 

le.of.how.to.wri 



000090 

7465 

2061 

2064 

6573 

6B20 

6163 

6365 

7373 

te.a.desk.access 



0000R0 

6F72 

792E 

2020 

4160 

6F6E 

6720 

6F74 

6865 

ory...Among.othe 



0000B0 

7209 

700D 

7B20 

0974 

6869 

6E67 

732C 

2069 

r. } . { . .things,.i 



ooooco 

7420 

7368 

6F77 

7320 

7468 

6520 

7374 

7275 

t.shows.the.stru 



000000 

6374 

7572 

6520 

6F66 

2061 

2044 

4 12C 

2068 

cture.of .a.DR, .h 



0000E0 

6F77 

2061 

2044 

4120 

6765 

7473 

2061 

6E64 

ow.a.DR.gets.and 


|| 

0000F0 

2072 

6573 

706F 

6E64 

7320 

746F 

0970 

007B 

.responds.to.}.{ 



000100 

2009 

6576 

656E 

7473 

2C20 

616E 

6420 

686F 

..events,.and.ho 



000110 

7720 

6120 

4441 

2060 

616E 

6167 

6573 

2074 

w.a.DR.manages.t 



000120 

6865 

2060 

656E 

7520 

6261 

722E 

0909 

0909 

he.menu.bar. 


|| 

000130 

0909 

0909 

097D 

007B 

2009 

7D0D 

7B20 

094R 

. }.{..}.{..J 



000140 

6566 

6620 

4061 

7474 

736F 

6E20 

616E 

6420 

eff.Mattson.and. 


I! 

000150 

5374 

6576 

6520 

5374 

6569 

6E2C 

2053 

7960 

Steve.Stein,.Sym 


2 


a 


If you like, you can click on the bug spray can in the far right of the menu bar to halt the program 
so you can use THINK Pascal’s debugging tools. 


To go back to THINK Pascal, choose Quit from the DA Shell’s File menu. 


Building the Desk Accessory 

Once you’re sure that the Hex Dump runs correctly, build it as a desk accessory that you can add to 
your system with the Font/D A Mover. Start by quitting THINK Pascal and going into the Finder. 
Duplicate HexDump . n and name the copy HexDump. Build . tu. You’ll modify this copy of the 
project so you can easily switch from testing to building the desk accessory. 

Note: When you build a desk accessory, device driver, or code resource, you 
should keep two separate project documents: one for debugging and one for 
building. To change from debugging to building (or vice versa), you only need to 
open a new project document instead of changing several options. The projects 
can share the same files. 


67 










THINK Pascal User Manual 


Your Hex Dump Folder should look something like this: 


=n=== He« Dump Folder Ftel 

13 items 24,905K in disk 14,460K availaj 

H^globals.p HexDump.tf.rsrc 

utilities .p 

lines .p UJ HexDump .7T 

windows .p 

files .p 

selection ,p 

H^qoto.p 

j|§|find.p 

dump .p 

fUSmain.p 

o 

o 

<? 0 

a 


Double-click on HexDump. Build. tu to start THINK Pascal again. 

Choose the Set Project Type... command in the Project menu and click on the Desk Accessory 
icon. 

In the Resource Information Name box, type in Hex Dump. This is the name that will appear in the 
Apple menu when you install your desk accessory with the Font/DA Mover. Check the Multi- 
Segment check box in the Resource Information section. 


68 

























THINK Pascal User Manual 


Remember that compiler variable, DAShell, that controls how your source files are compiled? You 
need to change it when you compile your program as a stand-alone desk accessory. Choose the 
Compile Options... command in the Project menu, and change this compiler variable: 


Compiler Uariables: 


THINK-Poscol = TRUE; 

THINK_PascaI_Uersion_4 = TRUE; 
EIems881 = TRUE; 

DRShelI = FRLSE; 


.o 


lo 


□ ‘USES’ Extensions 


l 1 1 

[ Cancel ) 


Code Generation: 

□ 68020/68030 □ Large Sets 

□ 68881/68882 □ Long Names 

□ Profile 


Now replace JiRuntime. lib with DRVRRuntime. lib. Hold down the Option key as you dou¬ 
ble-click on jiRuntime. lib in your project window. When THINK Pascal displays the standard 
file dialog, move to the Libraries folder, and double-click on DRVRRuntime. lib. 

Next remove the DA Shell source file from your project. Select the DA Shell file in the project win¬ 
dow and choose Remove from the Project menu. This command lets you take source files and 
libraries out of your project. 

Turn off all the compile options. The options are the D’s, N’s, V’s, and R’s to the left of the file 
names. Click on each option that’s in a box or hold down the Option key as you click on a box to 
turn off that option for all the files in the project. 


70 






Working with Projects 


7 


For example, if a file that uses the unit ODInit is in the wrong order, THINK Pascal displays this 
error message: 


“ODInit” isn't in the current project, hasn't been successfully 
'Wfcf complied, or is in the wrong build order. 


and points out the error: 


ID 


p? 


ObjectDraw.p 


program ObjtctDraw; 
{ v2.0d1 RMS 

{$!-} 

uses 

ODE vent, ODInit; 


8/4/89 


Creation. 


t— 7 777~77 —;——; "‘ne> 

1 __ _ » 


Segmenting a Project 

Most Macintosh applications are made up of several segments. Segments are collections of code 
that the Macintosh segment loader moves in and out of memory. 

Note: Segments correspond loosely to overlays in other development 
environments. 

The Macintosh limits segments to 32K, so if you’re writing a large program, you will have to seg¬ 
ment your code. To learn more on how the Macintosh uses segments, read Inside Macintosh II, 
Chapter 2, “The Segment Loader.” 

Note: When you’re running a program under the THINK Pascal environment, 
each segment can contain up to 64K. This lets you use segments that are over 32K 
before smart linking. But when you build your program, each segment must be 
under 32K after smart linking. 


103 






















THINK Pascal User Manual 


Making segments In the project window 

The easiest way to segment programs is to use the segment view of the project window. To see the 
segment view, click on the “Towers of Hanoi” icon (^) in the upper-right-hand corner of the 
project window. This is the segment view of the Hex Dump project: 


HeuDump.Build.Tt 


Options File (by segment) 


Size 






DRVRRuntime.lib 

2948 





Interface .lib 

10098 

D 

N 

V 

R 

g1oba1s.p 

0 

D 

N 

V 

R 

utilities .p 

772 

D 

N 

V 

R 

lines .p 

882 

D 

N 

V 

R 

windows .p 

2748 

D 

N 

V 

R 

files .p 

596 

D 

N 

V 

R 

main.p 

1868 





«95_MethTables» 

0 





«^_JSelProcs» 

0 






19916 

D 

...... 

V 

F 

selection .p 

562 

D 

N 

V 

R 

goto .p 

570 

D 

N 

V 

R 

find.p 

1876 

D 

N 

V 

R 

dump.p 

600 






3612 


10 


a 


Dotted lines separate the segments, and the name and size of the segment appear after the last 
entry for the segment. Each line in a segment’s listing is called a file entry. It represents the code 
that comes from a file or library. 

Note: For now, don’t worry about the entries «%_MethTables» and 
«%_SelProcs» . They’re described later in the section “Object Pascal and 
segmentation.” 

By default, THINK Pascal creates a segment called Main and places all the code from all the files 
there. To create a new segment, drag a file entry into the space just below the last file in the win¬ 
dow. To change the position of a segment, click on its name and drag it to a new position. To add a 
file’s code to an existing segment, just drag the file entry into the segment. Any segments that 
become empty are automatically deleted. 

The build-order view and the segment view are completely independent. If you change the build 
order, the segmentation does not change. If you change the segmentation, the build order stays the 
same. In the segment view you’re not moving files. You’re moving file entries. 


104 






Working with Projects 


7 


Naming segments 

You can edit the name and attributes of a segment. Double-click on a segment’s summary line to 
open a dialog box like this: 


Segment: 2 



Name: 

InitSeg 





I _™_ 1 


|| Attributes: 

28 





[ Cancel j 



To change the attributes, either click on the pop-up menu icon to select them or enter a new num¬ 
ber into the box. The possible attributes are Purgeable, Locked, Preload, and Protected By default, 
Purgeable and Protected are selected You may want to change the attributes if, for example, you 
don’t want a segment moved out of memory or you want it loaded into memory as soon as the 
program starts. 

Note: Don’t use %_SelProcs or %_MethTables as segment names. They are 
reserved by THINK Pascal. 

Making segments with the segmentation directive 

Sometimes, segmenting your project file by file isn’t powerful enough. For example, you may have 
a large File that doesn’t Fit into one 32K segment. 

In this case, you can create segments with the segmentation directive, { $S name }. This directive 
puts all the procedures and functions that follow it (up to the next segmentation directive or the 
end of the file) into the segment name. For more information on this directive, see Chapter 15, 
“Compiler Directives.” 


105 




THINK Pascal User Manual 


Here’s a n example of the segmentation directive: 

program myProgram; 

... Utility Routines ... 

{$S InitSeg} 

... Initialization Routines ... 

{$S TermSeg} 

... Termination Routines ... 

{$S Main} 

... Main Routines ... 

end. 

In this example, THINK Pascal creates three segments: InitSeg, TermSeg, and Main. It places 
the code as follows: 

In this segment... THINK Pascal places these routines... 

Main The utility and main routines. (THINK Pascal places all code that is 

not affected by a segmentation directive here. It also places code 
that follows a {$S Main} ora{$S} directive here.) 

InitSeg The initialization routines. 

TermSeg The termination routines. 

Choosing how to segment 

You can segment your project one of three ways: 

• File by file. All the routines in a file are in the file’s segment. If you want to put a rou¬ 
tine in a different segment, put it into a different file. If you want a segment to contain 
code from several files, move those files into that segment. This is the traditional way to 
segment applications in THINK Pascal, and it is still the best 

• Routine by routine. You place every routine into a segment with Segmentation direc¬ 
tives. THINK Pascal places the source files to the Main segment, but no code is in 
them. Use this method to port MPW Pascal programs to THINK Pascal quickly. 

• A little of both. Most routines are in their file’s segment, but some units are so large 
you must use the segmentation directive. Use this method when you have exceptionally 
large units. 

Note: Compiling a file that contributes to more than one segment can take a lot of 
time and memory. THINK Pascal needs enough memory to load in each segment 
that the file contributes to. 



Working with Projects 


7 


More about the segment view 

This is the segment view of the project window for the previous example: 


myProject.TT 
Options File (by segment) 
Runtime .lib 
Inter face.lib 

MB] v R my Program .p 

«96_MethTables» 

«S6_SelProcs» 

. Stefa 

«InitSeg » 
faffs*#' 
«TermSeg» 


Size 


14928 

10098 

242 

2 

0 

25274 


70 

74 

70 

74 




IG 


a 


In addition to file entries, these segments also contain directive entries. Directive entries are en¬ 
closed in angle quotes («») and represent code from segments created with the segmentation di¬ 
rective. Here, the directive entries are «InitSeg» and «TermSeg». The file entries represent 
code that wasn’t placed in a segment with a segmentation directive or code that was explicitly 
placed in the file’s segment with { $S} or { $S main}. Here, the file entries are myProgram. p, 
Runtime . lib, and Interface, lib. 

Note: «%_MethTables» and «%_SelProcs» are directive entries that THINK 
Pascal creates. They are described below. 

You can treat directive entries just like file entries. For example, you can drag the entry 
«TermSeg» into the segment InitSeg. The project window would look like this: 


s|~~js .. ... . ass 

myProject.iT 1 

..U |=| 

Options 

File (by segment) 

Size 

n 


Runtime .lib 

14928 



Interface .lib 

10098 


rDlfNlV R 

myProgram .p 

242 



« ^-MethT ables » 

2 



«^_JSelProcs» 

0 



Stefa 

25274 



«InitSeg » 

70 



«TermSeg» 

70 




144 




_ 


0 



107 









THINK Pascal User Manual 


Now, all the code that follows either a {$S InitSeg) directive or a { $S TermSeg} directive 
goes into the InitSeg segment. 

You can remove any directive entry with a size of 0 (zero). Simply select it, and select Remove 
from the Project menu. 

Note: You can’t remove a file entry with a size of 0. For example, interface files 
have a size of 0 but are still essential to your project 

Object Pascal and segmentation 

THINK Pascal adds two entries to every project: «%_MethTables» and «%_SelProcs». These 
contain the code that Object Pascal uses to dispatch messages. By default they’re both placed in the 
segment Main, but you can drag them anywhere. If you use Object Pascal heavily in your pro¬ 
grams, you may want to move «%_MethTables» into a segment by itself. If you don’t use Object 
Pascal at all, you can remove «%_SelProcs». 

Note: If you move «%_MethTables» out of Main, set the attributes of its new 
segment to be Preload and Locked. 

If the “Far Code” option is on, the entry «%_MethTables» can be up to 64K., instead of just 32K. 
However, because of this extended limit, you must put «%_MethTables» in its own segment 
whenever the “Far Code” option is on. For more information on the “Far Code” option, see 
“Building applications with large jump tables” in Chapter 12, “Building Projects.” 

Setting the Compiler Options 

The Options column in the project window displays the state of the debugging options for each file 
in the project. Enabling or disabling these options affects the code the compiler generates. Chapter 
15 goes into detail about the compiler options. This section gives you a brief overview. 

Option Meaning 

D Debug. Generates additional information between each Pascal statement to 

support stepping, stopping, and observing. 

N Names. Inserts the name of all routines into the code. This is useful for 

debugging with LightsBug and Macsbug. 

V Overflow Checking. Generates code that checks for integer arithmetic 

overflows. 

R Range Checking. Generates code that does range checking for array index¬ 

ing, assignments, and parameter passing. It also generates code that checks 
for nil pointer dereferencing. 

A box around the letter means that the option is enabled. By default, the D and N options are on. 
To turn the options on and off, click on the option letters. 


108 



Working with Projects 


7 


Note: It’s a good idea to turn the V and the R options on while you’re debugging 
your program. 

If you hold down the Option or Command key when changing an option, the new state of that 
option applies to all the files in the project. 

Getting Information on a Project’s Code & Data Size 

The Get Info... command in the Project menu shows how much code and data each file in your 
project produces. Choosing the command brings up this dialog: 


Runtime.lib 

Interface.lib 

PrintTraps.p 

Script.p 

Objlntf.p 

5 

iiiiii 

■ 


ijiii 

EmbedDefProo.p 

' 

i!i!l 

PrintDialogs.p 

!!|i: 

j( 

ODIntf.p 

ODMDefs.p 

Ijiii 

ODMenu.p 

ODTDraw Vindow .p 


ODTList.p 

jjj;j 

ODTPic'Window .p 

jjijj 

j:j:i 

ODTShape.p 


ODT Vindow .p 



Project Totals: 

Code: 59846 bytes 
Global Data: 2250 bytes 
Jump Table: 6640 bytes 

DialogUtils.p: 

Code: 4588 by tes 
Global Data: 10 bytes 
Jump Table: 272 bytes 



The list on the left contains all the files in your project. To examine a file, click on it. To examine 
several files in a range, hold down the Shift key and select the range. To examine several scattered 
files, hold down the Command key and click on each file. 

The right side displays the amount of code and data. On top, the “Project Totals” displays total 
amount of code and data in your project. Underneath is the amount of code and data that the 
selected file (or files) contributes to the total. 


This table explains what the dialog displays: 


Title 

Code 

Global Data 
Jump Table 


Meaning 

The amount of object code. This is same number in the Size column of 
the project window. 

The amount of global data. 

The size of the jump table, which contains the addresses of functions 
and procedures in your application. 


109 










THINK Pascal User Manual 


Customizing the Project Window 


The View Options... command in the Project menu lets you customize what appears in the 
project window. When you choose this command, you see this dialog box: 


Project Uieui Settings 


Options 

File (by build order) 

Size 

! [D][N]V[R] MemHacks 

32767 

IDlfNlfvlfRl 

Extremely v-i-d-e... 

10 


S filename □ unit name 

^ options □ uolume name 

S code size □ date file saued 

File Information 


| Geneuo 


[ OK ] [ Cancel ] 


Options - Boned indicates enabled 
D - Debug. Rllouis stepping, stopping, stack checking, Obseruing. 
N - Names. Insert Macsbug names into the code. 

U - Integer arithmetic ouerfloui checking. 

R - Range checking. 


The two pop-up menus let you choose the font THINK Pascal uses to display the file names in the 
project window. The check boxes let you choose the information that appears for each file. The 
box at the top of the dialog box shows you what the project window would look like with the 
current settings. 


Option 

filename 
options 
code size 
unit name 

volume name 
date file saved 


Meaning 

Displays the name of the file. 

Displays the compiler options. 

Displays the size of the compiled code. 

Displays the name of the unit. The unit name appears only after the 
file has been compiled. 

Displays the volume or folder the file is in. 

Displays the last date and time you saved the file within the THINK 
Pascal environment. 


110 






Working with Projects 


7 


The order that you click the check boxes determines the order of the display. In this example, the 
check boxes checked were filename, code size, date file saved, and options: 


Project Uieui Settings 


File (by build order) 

Size 

Date Saved 

Options 

MemHacks 

32767 

12/27/85 10:43 

HSvjB 


Extremely v-i-d-e... 

10 

01/02/86 23:07 

Seem 



E filename □ unit name 

E options □ uolume name 

E code size ^ date file saued 

File Information 


| Geneua 



( QIC ] [ Cancel ) 


Options - Boned indicates enabled 
D - Debug. Rllows stepping, stopping, stack checking, Obseruing. 
N - Names. Insert Macsbug names into the code. 

U - Integer arithmetic ouerflom checking. 

R - Range checking. 


Recovering Corrupted Projects 

When you’re debugging a program, you may run across errors that you can’t explain. Maybe you 
see an “Illegal Instruction” error you can’t trace. Or maybe THINK Pascal can’t open your project. 

A common cause of these problems is a corrupted project. When you run a faulty program under 
THINK Pascal, it can accidentally write to its project file and corrupt it. Writing to an uninitialized 
pointer or a pointer with the wrong value is frequently the cause. If you have a bug you can’t 
explain or have a project that THINK Pascal refuses to open, try these solutions. 

• Recompile your project. If you can’t compile or run your project, its object code may be 
corrupted. Choose Remove Objects from the Project menu and recompile your 
project. 

• Rebuild your project. If you can’t open your project, try opening another one. If it does 
open, rebuild your project from scratch, creating a new project file and adding the 
source files. 

• Make a backup of your project. If a program corrupts its project frequently, try making a 
backup of the project. Build the project from scratch and compile it with the Build 
command. When your project is corrupted, m ake a copy of the backup and use it. 

THINK Pascal automatically recompiles the files you changed since you made the 
backup. 


Ill 









Running Programs 

8 


Introduction 

This chapter shows you how to run a program in THINK Pascal. It tells you how THINK Pascal 
decides which files need to be recompiled, and what happens if there’s an error in your program. 

What you should know 

To run a program in THINK Pascal, you need a project document. If you don’t know about pro¬ 
jects, read the preceding chapter. If you want to experiment as you read this chapter, use one of 
the projects included in your THINK Pascal package or one that you created from the tutorials. 

Topics covered In this chapter 

• Running a program 

• When something goes wrong 

• Stopping your program 

• Compiling, building, and linking without running 

• Save options 

• Run options 

Running a Program 

To run a program, just choose Go from the Run menu. You’ll use the other execution com¬ 
mands — Step Into, Step Over, Go-Go, and Step-Step — when you debug your program. In the 
next chapter, you’ll learn how to use these commands. 

When you choose one of the commands in the Run menu, THINK Pascal examines your project to 
see which files need to be recompiled and relinked. If you’ve edited any source files or if you’ve 
added new source files to the project, THINK Pascal marks them for compilation. If you change the 
interface part of a unit, THINK Pascal marks all the files that use that unit. After marking the files, 
THINK Pascal compiles them by build order. 

Next, THINK Pascal links your program. It resolves references between files, and makes sure that 
names are not missing or defined more than once. 

If there are any files that have changed, THINK Pascal asks you if you’d like to save them before 
running the program. You can use the save options discussed below to tell THINK Pascal to always 
save your files before running or to never save your files before running. 



THINK Pascal User Manual 


When the program starts running, your program’s menu bar replaces the THINK Pascal menu bar, 
and a bug spray can appears on the right side of the menu bar. You’ll use the bug spray can to stop 
your program when you’re debugging it. 

When Something Goes Wrong 

If something goes wrong while THINK Pascal is compiling or linking your program, or if there is an 
error in your code, you’ll see a bug box telling you what went wrong. Here’s an example of a bug 
box: 



To get rid of the bug box, click the mouse or press the Enter or Return key. Of course, you still 
need to fix the bug! 

If your program has an error in it, THINK Pascal points out the error with a “thumbs down” next to 
the offending line in the file’s editing window. 



If the error happens while your program is running, and the offending file’s editing window is 
open, THINK Pascal shows you the error the same way. 


114 


























































Running Programs 


8 


If THINK Pascal finds a problem while it’s linking all the files in your project, it displays the mes¬ 
sage “Link Failed” and it shows you a Link Errors window. The messages in the Link Errors window 
tell you the names of undefined routines or the names of routines you’ve defined more than once. 


Link Errors 


undefined: “MISSINGPROCEDURE' 


m 



If you want to know in which files THINK Pascal found the errors, use the Check Link command 
in the Run menu. When you use this command, THINK Pascal reports the file names as well as the 
link errors. 

If the error happens while your program’s running and the file’s edit window is not open, the 
thumbs down will appear in the project window, next to the name of the appropriate file. 


—1 I - ■ 1 = Bullseue Tt -. = l *|~l 


Options File (by build order) Size 

£ 

o 

o 

Runtime .lib 18182 

Interface .lib 10098 

3^>[D][N][y][R] bullseye.p 166 

ri>h‘/C*& Sir* 28446 

0 0 

0 


Appendix D contains a list of error messages you might see when your program is compiling, 
linking, or running. 

Stopping Your Program 

To stop your program while it’s running, click on the bug spray can in the far right of the menu bar. 
Your program’s menu bar disappears, and THINK Pascal’s menu bar and windows come to the 
front so you can look at what your code is doing. You can also type Command-Shift-Period to stop 
your program. 

Note: You can stop your program only when it’s running code that was compiled 
with the Debug option on. If your program is running code that was compiled 
with the Debug option off, it will stop at the first place that was compiled with the 
option on. 


115 















































THINK Pascal User Manual 


If the file your program stops in has an open edit window, THINK Pascal points to the statement 
you’re stopped at. 

program Bullseye; ^ 

const 

scale = 8; Ijjlj; 

var 

hPos , vPos: integer; 

Radius,i:integer; 

begin 

ShowDr awing; 
hPos := 100; 
yPos := 100; 

PenMode(patXor); 

for i := 10 down to 1 do 
begin 

Radius := i * Scale; 

PaintCircle(hPos, yPos, Radius) jjijjj 

end 


If the file your program stopped in does not have an open edit window, THINK Pascal points to the 
file in the project window. 

Options File (by build order) Size [A I 

Runtime .lib 18182 |/\| 

Interface .lib 10098 —I 

5^[D][N][V]0 bullseye.p 160 I 

. TSSTSSSSsS .28440 


To continue execution, choose any of the execution commands — Go, Step Into, Step Over, Go- 
Go, or Step-Step — from the Run menu. To restart the program from the beginning, choose Reset 
from the Run menu before choosing Go. 


Note: THINK Pascal automatically resets your program when you edit a source 
file or modify your project. For more information, see “Restarting a Stopped 
Program” in Chapter 9. 


116 












































Running Programs 


8 


Compiling, Building, and Linking Without Running 

You can compile your program without running it. You might want to make sure that a file com¬ 
piles properly, or that you called all the procedures with the right number of arguments, or that you 
didn’t forget to define a procedure or function. 

To check the syntax of the file in the active edit window, use the Check Syntax command. This is 
a quick way to make sure your Pascal syntax is correct. To recompile the file, choose Compile. To 
see the Compile command, hold down the Shift key as you select the Run menu. 

To compile all the marked files, use the Build command. This command looks through your pro¬ 
ject to see which files have changed and recompiles them. If THINK Pascal finds any errors during 
compilation, you’ll get a bug box and a thumbs down. 

To make sure there aren’t any undefined symbols or any symbols defined more than once, use the 
Check Link command. This command does a Build and then links all the files in your project. If 
there are any link errors in your project, the Check Link command tells you which files contain 
multiply defined or undefined routines. 

Save Options 

Before THINK Pascal runs your program, it usually asks you if you want to save files that you’ve 
edited. It’s a good idea to save changes before you run. If you don’t save your changes, and your 
program crashes, you’ll lose any unsaved edits. 

The Save Options section of the Run menu lets you specify whether THINK Pascal saves the 
changes to your edited files before running. 

Option Meaning 

Auto-Save Saves any changes automatically before running your program. 

Confirm Saves THINK Pascal asks you if you want to save changes before running 
your program. 

Don’t Save Don’t save any changes before running the program. You’ll have to 

use the Save command in the File menu to save your changes. 

The Text and Drawing Windows 

The Text and Drawing Windows let you program even if you don’t completely understand the 
Macintosh Toolbox. This list describes what you can do with these windows: 

• You write to and read from the Text Window with the standard Pascal I/O routines, 
described in “9.0 Input/Output” in Chapter 17, “Language Reference.” 

• You draw to the Drawing Window with the Macintosh Toolbox graphics routines. 


117 




THINK Pascal User Manual 


• You can manipulate the windows from your program with the routines described in 
“10.6 THINK Pascal Window Manipulation Procedures” in Chapter 17, “Language 
Reference.” 

• You can print the windows with the Print... command. 

• You can save the contents of the windows with the Save As... command. THINK Pascal 
saves the contents of the Text Window as a Teach Text file and the contents of the 
Drawing Window as an ObjectDraw file. (ObjectDraw is the drawing program you 
create in Chapter 4, “Tutorial: ObjectDraw.”) 

Run Options 

THINK Pascal lets you setup certain run-time environment settings. Choose Run Options... from 
the Run menu. You’ll see this dialog box: 


Run-time Enuironment Settings 


Resources 


□ Use resource file: 

for resources used by the project. 


Text 

Window 


Text Window saues 


5000 


characters 


□ Echo to the printer 

□ Echo to the file: 


He Ilo world, x = 811.79. 


Monaco 




Memory 


Stack size: 

16 

kilobytes 

1 l ° K Jl 

Zone size: 

128 

kilobytes 

f -'i 

Cancel 

i- 





Resources 

The Resources section of this dialog lets you specify the resource file your program uses. When 
you click on the check box, you’ll see a standard file dialog box. Choose a resource file, and its 
name appears in the box. 


118 








Running Programs 


8 


Note: The resource file must be in the same folder as the project 

When you run your program in the THINK Pascal environment, THINK Pascal opens your resource 
file so you can access your resources. When you build your final application, THINK Pascal merges 
the resources from your resource file into the final file. 

To learn how THINK Pascal builds your project see Chapter 12, “Building Projects.” 

Text Window 

The Text Window section lets you specify how much text the window saves and the font to display 
in the text window. It also lets you redirect the output to the printer or to a file. 

To send all the output from the text window to a printer, check the Echo to printer check box. To 
send all the output from the text window to a file, click on the Echo to file check box, and name 
the file. 


Note: You can also print the Text Window with the Print. ..command and save its 
contents in a file with the Save As... command. 

Memory 

The Memory section lets you specify how much memory your program gets while it’s running in 
the THINK Pascal environment. THINK Pascal uses the stack for local variables and parameters. In 
most cases, 16K is plenty. But if a routine in your program uses a lot of local variables, or if your 
program does a lot of deep recursion, you might want to increase this value. 

The Zone size value tells THINK Pascal how much memory to set aside for your program’s heap. 
The heap contains your program’s code as well as any dynamically allocated data structures. 
Depending on the size of your program and on how much memory you allocate dynamically, you 
might want to make this value larger or smaller. 

If you’re running with MultiFinder, you may want to increase the size of the THINK Pascal partition 
when you increase the zone and stack sizes. 

Note: When you build your application, THINK Pascal uses the stack size value 
you specify. The zone size value applies only while you’re running in the THINK 
Pascal environment. 

For more information on stacks and zones, see Chapter 13, “Assembly Language,” Inside Macintosh 
II ; Chapter 1, “The Memory Manager,” and Inside Macintosh V7, Chapter 28, “The Memory 
Manager.” 


119 





Debugging Programs 

9 


Introduction 

It’s almost unheard of to write a program that runs perfectly the first time. THINK Pascal has several 
tools that help you track down bugs that creep into your program. This chapter shows you how to 
use them. 

The THINK Pascal editor catches syntax errors as you type in your program. And the project man¬ 
ager catches compiler and link errors such as undeclared variables and multiply defined symbols. 
These kinds of errors happen while you’re still writing your program. 

There are other errors that turn up while you program is running. You might discover that your 
program tries to divide by zero, or that it’s trying to store a value into the seventh element of a six 
element array. THINK Pascal helps you catch run time errors by displaying a thumbs down icon 
next to the line that contains the error. 

The most insidious errors are errors of intention. Your program runs, but it doesn’t do the right 
thing. These errors occur when you forget to account for a special case or when the code you write 
doesn’t do what you think it does. 

No compiler or development system can catch these errors of intention for you, but THINK Pascal 
gives you a set of tools that makes finding errors easier and faster. THINK Pascal lets you watch 
your program as it runs. You can step through each line of your program, stop at any point, and 
examine and modify any variable. If you like, you can make temporary fixes to your program 
without recompiling, so you can see if your fixes really work. 

Note: THINK Pascal also provides a more advanced debugging tool — LightsBug. 

See Chapter 14 after you read this chapter to learn more about LightsBug. 

Topics covered in this chapter 

• Debugging in THINK Pascal 

• Following the finger 

• Stepping through your program 

• Stop Signs 

• Restarting a stopped program 

• The execution commands 

• The Observe window 

• The Instant window 

• Examining compiled code 



THINK Pascal User Manual 


Debugging in THINK Pascal 

The basic trick of debugging is to find out what your program is really doing instead of what you 
thought it was supposed to do. The first thing to do is to run your program in a controlled way, so 
you know exactly what happens when your program is running. THINK Pascal lets you control 
program execution several ways. 

• You can use the Step Into or Step Over command to step through your program one statement 
at a time. The execution finger appears next to the line about to be executed. Your program 
stops after each statement 

• You can use the Step-Step command to let THINK Pascal step through each statement automat¬ 
ically. To see this command, hold down the Option key and choose the Run menu. This com¬ 
mand steps through your program a statement at a time, pausing briefly between statements to 
update the LightsBug and Observe windows. 

• You can insert one or more Stop Signs anywhere in your code. If you use the Go or Step-Step 
commands to run your program, it will stop whenever it encounters a Stop Sign. With the Go- 
Go command, the program only pauses at a Stop Sign to update the LightsBug and Observe 
windows. 

• You can click on the bug spray can to stop the program at any point. 

• You can type Command-Shift-Period to stop your program. 

Note: To use the THINK Pascal debugging tools, make sure that you’ve compiled 
your files with the Debug option on. 

Sometimes, just slowing program execution is enough. By watching the output of the program at 
the same time as you watch the source lines being executed, you can see what’s going on. Often, 
though, you need to know the values of variables and expressions, not just which statement is be¬ 
ing executed. For this kind of debugging, you can use the Instant and Observe windows. 

The Observe window lets you type in (or copy from your source file) any number of valid Pascal 
expressions (including variable names) whose value you want to know about. THINK Pascal up¬ 
dates the values in the Observe window when your program is stopped or whenever your program 
pauses between statements. 

If your program is already stopped, you can find out the current value of a variable or expression 
by typing it into the Observe window and pressing the Enter key. 

The Instant window takes things one step further. You can actually change the value of a variable 
or expression, or insert additional statements into your program, and have them executed on the 
spot — in the context of the program at the point at which it stopped. 


122 



Debugging Programs 9 


Following the Finger 

Whenever your program is stopped or paused, the execution finger points to the statement about 
to be executed. 



If the file you’re stopped in doesn’t have an open edit window, the execution finger points to the 
file in the project window. 

Note; To see the execution finger, the file must be compiled with the Debug op¬ 
tion on. If you compile a file with the Debug option off, you’ll never see the 
execution finger in it, even if the file has an edit window. 

When the finger moves from one window to another, the new window becomes the active win¬ 
dow. If you want to keep another window frontmost as you step through your program, you can 
turn off the Auto-Show Finger option in the Debug menu. For instance, if you want to keep the 
Observe window from being covered up as the edit windows become active, you would turn 
Auto-Show Finger off. The downside of turning this option off is that if an edit window is 
obscured, you won’t be able to see the execution finger. 

Note; It’s a good idea to keep Auto-Show Finger off when you’re debugging 
how your application handles update events. 

When your program is stopped, you can scroll through the editing window or switch to other win¬ 
dows to look at other parts of your program. The Show Finger command in the Debug menu 
makes the window with the execution finger the active window and scrolls until the finger is 
visible. 


123 





























































THINK Pascal User Manual 


Stepping Through Programs 

To run a program one statement at a time, choose either Step Into or Step Over from the Run 
menu. THINK Pascal executes the first statement in the program, updates the Observe and 
LightsBug windows, and then stops. Choosing either command again continues with the next 
statement. The Step Into command steps into procedure and function calls, moving the execution 
finger into the procedure or function called. The Step Over command steps over function and 
procedure calls, keeping the execution finger within the current block. 

To exit the procedure or function you’re in, choose the Step Out command. THINK Pascal contin¬ 
ues executing until it returns from the current routine, and then stops. You’ll find this command 
especially useful if you accidentally step into a routine with the Step Into command. 

Stepping through a program can take a long time, so you’ll normally use the step commands when 
you want to take a very close look at a part of your program. The Step-Step command is the auto¬ 
matic version of Step Into. It executes your program faster than Step Into, but slowly enough so 
you can watch the program’s execution. THINK Pascal updates the Observe and LightsBug win¬ 
dows between statements. To see this command, hold down the Option key and choose the Run 
menu. 

Stop Signs 

Sometimes even stepping automatically is too slow. You may want to run your program at full 
speed up to a specific point, and then stop it. Then you can either start stepping or tracing, possibly 
using the Observe window. 

Stop Signs let you specify the statements where you want to interrupt execution of your Pascal 
program. If you run your program with Go or Step-Step, the program runs until it reaches the Stop 
Sign, and then it stops. The statement at the Stop Sign is not executed. 

The Go-Go command is the automatic version of Go. It pauses momentarily at each Stop Sign just 
long enough to update the values in the Observe and LightsBug windows. To see this command, 
hold down the Option key and choose the Run menu. If there are no Stop Signs in the editing 
window, Go-Go is equivalent to Go. 


124 



Debugging Programs 


9 


To put Stop Signs in your programs, choose the Stops In option from the Debug menu. A Stop 
Sign appears in the lower left-hand corner of the active editing window, and a vertical bar appears 
along the left side. 


=[~~1^ = ^ === == Rullseue.n ■ i 1 1 = | 



program Bullseye; 
const 

Scale = 8; 

var 

hPos, vPos: integer; 

Radius, i: integer; 

begin 

hPos := 100; 
vPos := 100; 

PenMode(patXor); 

for i := 100 dovnto 1 do 
begin 

Radius := i * Scale; 

PaintCircle(hPos, vPos, Radius) 

end 

end. 

O 

O 



Q 


When you move the cursor into the bar on the left side of the edit window, the cursor turns into a 
Stop Sign. Move the Stop Sign until it is directly to the left of the statement you want execution to 
stop before, and click. A Stop Sign remains in the stop bar like this: 


: Bullseye.p ".——Pll| 


program Bullseye; 
const 

Scale = 8; 

var 

hPos, vPos: integer; 

Radius, i: integer; 

begin 

hPos := 100; 
vPos := 100; 

PenMode(patXor); 

for i := 100 dovnto 1 do 
begin 

Radius := i * Scale; 

PaintCircleChPos, vPos, Radius) 

end 

end. 

O 


01 1I1I111I1BIIII1IIIIIP 



125 






































































































THINK Pascal User Manual 


You can put in as many Stop Signs as you want, but only on lines that contain Pascal statements. 
You can’t put a Stop Sign before a comment, a declaration, a label, or an empty statement. 

To use Stop Signs in a file, the project must contain debug information for the file. If you try to put 
a Stop Sign in a file that has the Debug option turned off, THINK Pascal displays a dialog asking if 
you want to turn the option on. If you click Yes, THINK Pascal turns the option on and inserts the 
Stop Sign. If you click No, THINK Pascal leaves the option off and doesn’t insert the Stop Sign. 

If you turn the Stops In option off, THINK Pascal hides and ignores all your Stops Signs. If you 
turn the option on again, the Stop Signs reappear, and THINK Pascal will stop at them when you 
run your program. If you save a file with the Entire Document option, any Stop Signs placed in the 
file will be saved as part of the file. 

To remove a Stop Sign, click on it. To remove all the Stop Signs from the active window, choose 
Pull Stops from the Debug menu. To remove all the Stop Signs from all the open windows, 
choose Pull All Stops. To see Pull All Stops, hold down the Option key and select the Debug 
menu. 

Restarting a Stopped Program 

When you stop a program with the bug spray can or with a Stop Sign, you don’t have to start it all 
over from the beginning. If you choose one of the execution commands — Go, Step Into, Step 
Over, Step Out, Go-Go, or Step-Step — from the Run menu, the program continues with the next 
statement. 

THINK Pascal will reset your program to start again from the beginning when you edit a source file, 
choose a command that can modify your project (such as Add File, Set Project Type, or Compile 
Options), move a file in your project window, or choose the Reset command from the Run menu. 
If you try to change a source file or project, THINK Pascal warns you with a dialog like this: 



If you answer Yes, THINK Pascal resets your program and proceeds with the command or editing. 
If you answer No, THINK Pascal cancels the command or editing. If you don’t want to see these 
warnings, select the Quietly Auto-Reset option from the Debug menu. 

Note: If you reset your program by choosing Reset or moving a file in your 
project window, THINK Pascal does not warn you with a dialog. 


126 





Debugging Programs 


9 


The Execution Commands 

THINK Pascal gives you several execution commands, each of which runs your program a different 
way. This chart summarizes what the different execution commands in the Run menu do: 


Command 

Go 

Step Over 
Step Into 
Step Out 


Description 

Runs your program, stopping at Stop Signs (or break points) 
Executes the next statement, without stepping into procedures and 
functions 

Executes the next statement, stepping into procedures and 
functions. 

Steps out of the current procedure or function and stops 


The Option key changes a few of the execution commands into automatic versions. Go becomes 
Go-Go, and Step Into becomes Step-Step. The automatic versions pause when their counterparts 
would stop. Choosing them is like choosing Go or Step Into over and over again. To see the 
automatic commands, hold down the Option key as you choose the Run menu. 


Command 

Go-Go 

Step-Step 


Description 

Runs your program, pausing at Stop Signs 

Runs your program, pausing after each statement and stopping at 
Stop Signs. 


The Observe window 

The Observe window lets you track the value of a variable or expression while your program is 
running. This window takes the place of the old debugging technique of inserting writeln state¬ 
ments into your program to print out the values of variables or expressions. 

Note; In fact, only values that can be printed with writeln can be observed. 

To type an expression in the Observe window, choose Observe from the Debug menu. 


Obserue 


100 

hPos 

o 

Enter an expression 



-pert I ::;:::::!:;:;:;:!:;:;:!:!:;:;:;:;:;:;:;:;:; 1 


o 

..*.... 



IBI 


You can type in any valid Pascal expressions in the cells to the right of the vertical bar in the mid¬ 
dle of the window. You can copy an expression from your program, from the Instant window, or 
from another Observe window cell and paste it into the Observe window. The expressions will be 
evaluated and the results appear in the left cells whenever you press the Enter key or when your 
program stops or pauses. 


127 




















































































THINK Pascal User Manual 


The Observe window uses the point at which your program stopped for the context of its 
expressions. Once the program finishes, the Observe window displays the message “No context.” 

It is relatively harmless to type invalid expressions or expressions with run-time errors in the 
Observe window. An abbreviated error message appears in the left hand cell. 

Some handy tips for using the Observe window: 

• To observe floating point numbers with precision, use the stringof function de¬ 
scribed in Section 10.9.4 of Chapter 17. 

• You can use Observe to convert hexadecimal numbers to decimal. Type '$’ followed by 
the hex number. The equivalent decimal value appears in the left cell.. 

• You can convert decimal numbers to hexadecimal by casting them to pointers. For 
example Pointer (-1) yields FFFFFFFF. 

• You can use the Observe window to examine variables and expressions if execution is 
stopped because of a run-time error. This powerful debugging feature can help you 
figure out the cause of the run-time error. 

This Observe window illustrates some of the tips: 


3.14159265358979 

stringofiCpi : 1 : 14) |£H 

3.141593 

Pi t 1 

-1330 

$FACE liil 

FFFFFFFF 

Pointer(-I) R5] 


VUl:|:|j^ 


THINK Pascal lets you save the contents of the Observe window. When the window is active, 
choose the Save As... command from the File menu. To open a saved Observe window, use the 
Open... command in the File menu. The saved window replaces the contents of the current 
window. 


128 





















































































Debugging Programs 


9 


The Instant window 

Any time your program is stopped, you can use the Instant window to execute any THINK Pascal 
statements. Choose Instant from the Debug menu if the Instant window is not visible. Type in and 
edit any Pascal statements in the window just as you would in an edit window. Then click the Do 
It button to execute the statements. 


Instant 


[Do It 86;] 

hPos := 80; 




Note: If you use Command-; (Command-Semicolon), you can run the code in the 
Instant window without making it the active window. 

Almost any Pascal statement is valid in the Instant window if it is legal at the point in the program 
at which execution is stopped. The statements in the Instant window are executed as if they were 
inserted into your program at the point where execution paused. You can even use the Instant 
window after a run-time error occurs. You might be able to fix the cause of the error and continue 
executing your program. 

Note: You cannot use these statements in the Instant window: goto, exit, or 
interactive I/O like readln . 

The Instant window lets you try out new code. Type the new code in the Instant window and exe¬ 
cute it. If it doesn’t work, try something else. You can do this until your code works. Then copy the 
new code from the Instant window and paste it into the program. 

Note: If you call a procedure containing Stop Signs from the Instant window, the 
Stop Signs are ignored. 

THINK Pascal lets you save the contents of the Instant window. When the window is active, choose 
the Save As... command from the File menu. To open a saved Instant window, use the Open... 
command in the File menu. The saved window replaces the contents of the current window. 

Examining Compiled Code 

A special mode of the execution commands (Go, Step Into, Step Over, Step Out, Go-Go, and 
Step-Step) lets you use a low level debugger like TMON or Macsbug to examine compiled code. 
To examine the compiled code for a particular statement in your program, hold down the Shift key 
and choose an execution command from the Run menu. Instead of executing the next statement, 


129 























































































THINK Pascal User Manual 


THINK Pascal will drop into the low level debugger just before an RTS instruction that leads to 
your code. 

To examine your compiled code in TMON, choose an execution command and open an assembly 
window anchored to the PC. In Macsbug, type T, then IL PC to display the code. If you compiled 
your program with the Names option on, you’ll see the name of the subroutine in the low level de¬ 
bugger. When you’re through examining the code, just choose the Exit command in TMON or the 
G command in Macsbug. 

Note: If you don’t have a low-level debugger, choosing an execution command 
with the Shift key down is the same as choosing the command without the Shift 
key down. 


( 




Units and Libraries 

10 


Introduction 

This chapter goes into more detail about the components of a Pascal program. You’ll learn how to 
create and use units and libraries. 

A unit is a file that is part of a larger program. Units usually handle a certain kind of action or deal 
with a particular data structure. A unit can be generic, but more often it is tailored for its specific 
role in your program. Other programming languages use the terms module or package instead of 
unit. 

A library is a collection of precompiled functions and procedures. Like units, libraries usually deal 
with a kind of action or handle some data structure, but libraries are more generic. You can use 
libraries in any program. 

Topic covered In this chapter 

• Using units 

• Writing units 

• Using libraries 

• Writing libraries 

Using Units 

A THINK Pascal program usually consists of a main program and several units. A unit is a collection 
of constants, types, variables, and procedures and functions that you use in your program to handle 
a particular set of actions or data structures. For instance, in a drawing editor, a unit might handle 
drawing shapes. In fact, this is what the ODTShape unit of the ObjectDraw example in your THINK 
Pascal package does. 



THINK Pascal User Manual 


To use a unit in your program or in another unit, you put the unit name in a uses clause in the 
program or unit. For example, if your program were to use a unit called Conversions, this is 
what the uses clause in your program would look like: 

program Gazelle; 

uses 

Conversions; 

... types and vars ... 


begin 

... the program ... 

end. 

Units let you break up your program into small, manageable pieces. Usually, you’ll make changes 
only to one unit a time, and then test the changes. Because THINK Pascal recompiles and relinks 
only the units that have changed, you’ll be able to work faster if you use units. 

When you view the project window by build order, all units must be listed in the order you use 
them. In other words, files that are used must precede the files that use them, with the main 
program always last. See Chapter 7, “Working with Projects,” to learn how to change the build or¬ 
der. 

Writing a Unit 

A unit has two parts: an interface and an implementation. The interface section declares all the 
constants, types, variables, procedures, and functions that other files can see. The implementation 
section contains the code for the visible procedures and functions. The implementation section can 
also define its own constants, types, variables, procedures, and functions, but these will be private 
to the unit. 

A unit begins with the keyword unit followed by a unit name. The name of the unit is not neces¬ 
sarily the same as the file name, but it’s less confusing if you use the same name for them. Just 
remember that when you use a unit, you give the unit name in the uses clause, not the file name. 

Note: You can use the View Options... dialog to have THINK Pascal display the 
name of the unit as well as the file name in the project window. The unit name 
shows only after the unit has been compiled. See Chapter 7, “Working with 
Projects, ” for more information. 

The interface section follows the unit name. The interface section contains the public constants, 
types, variables, procedures, and functions that your unit defines. For procedures and functions, 
you provide only the headers (along with the parameter lists). 


132 


The implementation defines all the private constants, types, variables, procedures, and functions. 
The implementation section also defines the bodies of the procedures and functions you declared 
in the interface section. The procedure and function headings in the implementation section can 



Units and Libraries 


10 


contain parameter lists only if they match the parameter lists in the interface section. Here’s an 
example of a unit. 

unit Calculations; { Sample Unit - doesn't do much } 

interface 

uses 

SANE; { The RoundPre type is defined in SANE } 

var 

DisplayWidth : integer; { This variable is exported } 

{ Public procedures and functions. } 

{ The bodies are in the implementation section } 

procedure Initialize (Precision: RoundPre); 
function Square (aNumber: longint) : longint; 

implementation 

const 

ConstantPrivateToCalculations = 42; 

var 

RoundPrecision: RoundPre; 

procedure Initialize (Precision: RoundPre); 

begin 

RoundPrecision := Precision; 

SetRound (RoundPrecision); 

end; 

function Square (aNumber: longint) : longint; 

begin 

Square := aNumber * aNumber; 

end; 

procedure PrivateToCalculations(x: integer); 

begin 

end; 

end. 


133 




THINK Pascal User Manual 


The program that uses this unit would be in another file and would look something like this: 
program Gazelle; 


uses 

SANE, Calculations; 


var 

aNum : longint 
{ more declarations 


begin 

Initialize(TowardZero) ; 
aNum := Square(1961) ; 

end. 


{ The program uses SANE because } 
{ the TowardZero constant is } 
{ defined there, and because } 
{ Calculations uses it in its } 
{ interface part } 


{ Public proc in Calculations unit } 


In this example, the main program would not be able to call the procedure 

PrivateToCalculations or use the constant ConstantPrivateToCalculations because 
both are defined only in the implementation section of the unit and not in the interface. 

The uses clause 

The uses clause specifies the dependencies between the files that make up a program. If your unit 
uses something that’s defined in another unit, that other unit needs to appear in your unit’s uses 
claus. Everything in the used unit’s interface clause appears as though it’s in the unit that contains 
the uses clause. THINK Pascal uses this clause to determine which files are affected by an edit. 
Whenever you change the interface section of a unit, THINK Pascal recompiles all the files that use 
it 

The “USES Extensions” option lets you choose between two ways that THINK Pascal can interpret 
your uses clauses. To see the option, choose Compiler Options... in the Project menu. 

If you turn on the “USES Extensions” option, THINK Pascal lets you use these features: 

• Propagated uses. If your unit uses other units, any unit that uses your unit also uses 
those units automatically. 

• Implementation uses. You can put a uses clause in a unit’s implementation section. 


134 




Units and Libraries 10 


Propagated uses lets you shorten your uses clauses. If your unit uses a lot of other units, any unit 
that uses your unit automatically uses those other units. THINK Pascal propagates the other units 
from your unit. For example, say you write this: 

unit MyShapesUnit; 

interface 

uses 

Circles, Squares, Triangles, Rectangles; 

This unit uses MyShapeUnit and all the units MyShapeUnit uses (Circles, Squares, 
Triangles, Rectangles): 

unit MyPictureUnit; 

interface 
uses 

MyShapeUnit; 

var 

aSquare: RedSquare; 
aTriangle: LoveTriangle; 
aCircle: TrafficCircle; 

Even though MyPictureUnit doesn’t contain Circles, Squares, and Triangles in a uses 
clause, it can use what they declare. THINK Pascal propagates those units into MyPictureUnit 
from MyShapeUnit. 

Implementation uses lets you put your uses clause close to the code that needs it. (Your code 
needs a uses clause if it refers to something that’s defined in a unit in the uses clause.) If a unit’s 
implementation section needs a unit but the interface section doesn’t need it, you can put that unit 
in a uses clause in the implementation section. If the interface section needs the unit, it must be in 
a uses clause in the interface section. For example, here is the rest of MyPictureUnit: 

unit MyPictureUnit; 

interface 

uses 

MyShapeUnit; 

var 

aSquare: RedSquare; { Defined in Squares unit } 

aTriangle: LoveTriangle; { Defined in Triangles unit } 

aCircle: TrafficCircle; { Defined in Circles unit } 

procedure DrawPicture; 

implementation 

uses 

MyPrivateColorsUnit; 
procedure DrawPicture; 

var 

aColor: Mauve; 


{ Defined in Squares unit } 

{ Defined in Triangles unit } 
{ Defined in Circles unit } 


135 



THINK Pascal User Manual 


begin 

end; 


end. 

Since only the implementation section needs MyPrivateColors unit, you can put it in a 
implementation uses clause. 

THINK Pascal does not propagate implementation uses clauses. It propagates only interface uses 
clauses. This fact helps you create private units that you can use but that other people can’t. For 
example, say someone writes the unit AGalleryUnit that uses MyPictureUnit. That person 
can use what’s defined in MyPictureUnit, but not what’s defined inMyPrivateColorsUnit. 

If you turn off the “USES Extensions” option, you can’t use propagated uses or implementation 
uses. For example, this is how you would need to rewrite MyPictureUnit: 

unit MyPictureUnitll; 

interface 

uses 

Circles, Squares, Triangles, MyShapeUnit, MyPrivateColorsUnit; 

var 

aSquare: RedSquare; { Defined in Squares unit } 

aTriangle: LoveTriangle; { Defined in Triangles unit } 

aCircle: TrafficCircle; { Defined in Circles unit } 


Since THINK Pascal does not propagate the units used in My Shape sUnit, you need to explicitly 
include Circles, Squares, and Triangles in the uses clause. Notice that you don’t need to 
include the Rectangles unit since you don’t use it. Since you can’t use implementation uses, 
you must put MyPrivateColorUnit in an interface uses clause. Anyone who uses 
MyPicutureUnitll will be able to use whatever’s in that private unit. 

Using Libraries 

A library is like a unit in that it contains procedures and functions to perform an action or to ma¬ 
nipulate a particular data structure. But unlike units, a library is made up of compiled code and can 
consist of more than one Pascal File. 

To use a library, you simply add it to your project with the Add File... command in the Project 
menu. Most of the time, a library has an associated interface File. The interface file is a unit that 
contains the type declarations and calling sequences for the procedures and functions defined in 
the library. To add the interface file, use the Add File... command. 

Your THINK Pascal package comes with several libraries. The next chapter tells you what’s in each 
library. 


136 



Units and Libraries 


10 


Writing Libraries 

Writing a library is like writing a unit. In fact, a library is made up of one or more units. The differ¬ 
ence between adding a library into your project and adding the units that comprise the library into 
your project is that a library consists of compiled code whereas you would have to compile each 
unit. In most cases, you won’t even have the source code for libraries. 

To create a library, make a new project and add all the units that comprise it. Then use the 
Remove command in the Project menu to remove Interface, lib and Runtime. lib. If you 
leave these two libraries in your library, any project that uses them and your library will have mul¬ 
tiply defined symbols. Then use the Build library... command in the Project menu to create your 
library. A standard dialog box will appear asking you to name the library. By convention, libraries 
end in . lib. THINK Pascal builds the library in a format that is compatible with MPW . o files. 

Note: Even though they use the same format, compilers that create . o-compatible 
files can’t use THINK Pascal libraries, and THINK Pascal can’t use most of their . o 
files. For more information, see “Using . o Files,” Appendix C. 

Your library must conform to these two constraints: 

• It contains at least one file . 

• It contains only units, no main program. 

Writing the Interface file 

Because the library consists of compiled code, there’s no way for your program to know how to 
call the procedures and functions in it. You need to create the interface file to let the program that 
uses your library know what the routines are called and how to call them. The interface file also 
defines the public types, variables, and classes you use in the library. 


137 



THINK Pascal User Manual 


For instance, suppose you created a library, Names .lib, that contains types, variables, proce¬ 
dures, and functions that deal with names in a list. Your interface file might be called 
Name s I nt f. p and look like this: 

unit Nameslntf; 

interface 

type 

{ This is a type your program can use. The library may } 

{ define private types that your program can't "see" 1 
Str32 = string [32]; 

NameRec = record 

FirstName: Str32; 

LastName: Str32; 
end; 

var 

{$J+} 

ThisName: NameRec; 

NextName: NameRec; 

{$J-} 

function AddName(first: Str32, last: Str32): integer; 
function FindName(ix: integer; var theName: NameRec):Boolean; 
procedure DelName(ix: integer); 

implementation 

{ These declarations are optional because THINK Pascal } 

{ defaults them to external. } 

function AddName(first: Str32, last: Str32): integer; 
external; 

function FindName(ix: integer; var theName: NameRec):Boolean; 
external; 

procedure DelName(ix: integer); 
external; 

end. 

To use the library, you would add Name slnt f. p and Names . lib to your project. The unit that 
calls procedures and functions from Names .lib would have this clause in it: 

uses Nameslntf; 

The interface file looks just like a unit. The interface section shows what procedures and functions 
are public and how they should be called. The implementation section is a little bit different. 
Instead of defining the bodies of the procedures and functions, it contains the routine headers and 
then the directive external. 

Note: If there is no definition of a procedure or function declared in the imple¬ 
mentation part, THINK Pascal assumes that the procedure or function is external. 


138 



Units and Libraries 


10 


It’s a good idea to declare these routines external explicitly to make your 
intentions clear to others who use your libraries. 

To declare public variables in an interface file, you must use the External Variable directive { $ J±}, 
which turns on and off the External Variable option. This option tells THINK Pascal not to allocate 
space for the following variables. {$ J+} turns on the option on , and{ $ J-} turns it off. If you don’t 
use this directive in your interface file, THINK Pascal declares space for your variables twice: once 
in the library and again in the interface file. 

Note: For more information on using compiler directives and the External Variable 
directive, see Chapter 15, “Compiler Directives.” 

To declare public classes in an interface file, you must also use the External Variable directive 
{ $ J±}. When THINK Pascal comes across a class declaration, it generates code to resolve calls to 
its methods. The External Variable directive tells THINK Pascal not to generate that code. If you 
don’t use this directive in your interface file, THINK Pascal generates that code twice: once in the 
library and again in the interface file. For example, this class declaration will not generate that 
code: 


type 

{$PUSH} 

1$J+) 

MyWindow = object (Window) 
windowData: Handle; 
subWindow: ToolWindow; 

procedure Hit (where: Point); 
override; 
procedure Draw; 
override 
end; 

{$POP} 

Note: At the end of the variable or type declaration section, you must turn off the 
External Variable option (with either { $ J-} or { $POP}). 

The external directive 

The external directive tells the compiler that the body of the procedure or function is not there, 
but that it should try to find it when the linker tries to link the program. 

Usually, you use the external directive in the implementation section of interface files for li¬ 
braries or to access procedures and functions that were originally written in assembly language. 
But you can use it to describe the calling sequence for a procedure or function that isn’t in a used 
unit. 


Note: To learn more about using assembly language routines in THINK Pascal, 
see Chapter 13, “Assembly Language.” 


139 




THINK Pascal User Manual 


For example, if you added the library Names. lib from the example above into your project, and 
you didn’t want to add the interface file, you could just write: 

function AddName(first : Str32, last : Str32) : integer; 
external; 

in the file that uses AddName to define the calling sequence for the AddName function. 

Generally speaking, you should limit use of the external directive to an interface file. 


140 



Using Predefined Routines 

11 


Introduction 

THINK Pascal predefines all of the standard Pascal procedures and functions as well as the most 
common Macintosh Toolbox routines. Your THINK Pascal package also includes several libraries 
for those routines that aren’t built into the compiler. This chapter shows you what you need to do 
to access the standard Pascal procedures like write, writeln, abs, etc. and how to access the 
Macintosh Toolbox routines described in Inside Macintosh. 

Topics covered In this chapter 

• Calling standard Pascal routines 

• Calling Macintosh Toolbox routines 

Calling Standard Pascal Routines 

THINK Pascal provides a large number of predefined procedures and functions. When you create a 
new project, two libraries are automatically added to it The library Runtime. lib contains all of 
the standard Pascal routines like writeln, readln, and abs, as well as routines that the com¬ 
piler uses for sets, 32-bit mulitplications, and so on. Runtime. lib also contains some procedures 
and functions for compatibility with Symantec’s (formerly Apple’s) Macintosh Pascal. For a 
complete description of the THINK Pascal predefines, see Sections 9 and 10 of the Chapter 17, 
“Language Reference.” 

Depending on the type of project you’re building you may use different versions of 
Runtime. lib. The default Runtime. lib that’s included in every THINK Pascal project you cre¬ 
ate is rather large because it’s supporting all of the Pascal input/output and the code that manages 
the Text window. 

If you’re writing a Macintosh application, and you’re not using any of the Pascal input/output rou¬ 
tines, you can use a smaller version of Runtime. lib called pRuntime. lib. This version of the 
library does not contain any Pascal input/output routines, so you can’t use the Text or Drawing 
windows. 

If you’re writing a desk accessory, device driver, or code resource, you cannot use Runtime .lib 
or pRuntime .lib because both libraries reference their globals through register A5. For code 
resources, use RSRCRuntime. lib. For desk accessories and drivers, use DRVRRuntime. lib. 
These libraries are similar to pRuntime. lib and do not contain any Pascal input/output routines, 
so you can’t use the Text or Drawing windows. Unlike pRunt ime. lib, they use register A4 to 
access their globals. The next chapter shows you how to build these kinds of projects. 



THINK Pascal User Manual 


Calling Macintosh Toolbox Routines 

THINK Pascal lets you use all the Macintosh Toolbox routines described in Inside Macintosh I-VI 
including those marked [Not in ROM] . To use the Toolbox routines, call them exactly as they 
appear in Inside Macintosh. 

Most of the Toolbox routines in Inside Macintosh 7-V7are predefined in THINK Pascal, so you 
don’t have to do anything special to use them. The constants, types, and routines are built into 
THINK Pascal. The library Interface. lib contains the “glue” code for Toolbox routines that 
aren’t stack-based. 

THINK Pascal generates in-line calls for all of the stack-based traps. For the register-based traps, 
routines marked [Not In ROM], and for routines that work off dispatched traps, THINK Pascal 
uses the “glue” code in Interface. lib so you can call them as Pascal procedures and functions. 

For the less common routines, you need to add specific libraries and interface files to your project. 

Note: This section assumes you already know what interface files and libraries 
are. If you need to learn about them, see Chapter 10, “Units and Libraraies.” 

Toolbox Interfaces 

The Toolbox interfaces are organized along the lines of the Inside Macintosh chapters. Each file 
contains the routines described in a different chapter of Inside Macintosh. For example: 

This file... Contains the routines described in this chapter... 

Event s . p Inside Macintosh 7, Chapter 8, “The Toolbox Event Manager” 

Windows . p Inside Macintosh I t Chapter 9, “The Window Manager” 

Menus . p Inside Macintosh 7, Chapter 11, “The Menu Manager” 

The following interfaces are built into THINK Pascal. You don’t need to include them in your 
project or your unit’s uses clause. 

Controls.p Desk.p Devices.p 

Dialogs.p Disklnit.p Errors.p 

Events.p Files.p Fonts.p 

GestaltEqu.p Lists.p MacPrint.p 

Memory.p MemTypes.p Menus.p 

OSEvents.p OSIntf.p OSUtils.p 

Packages.p Packlntf.p PaletteMgr.p 

Pickerlntf.p QDOffscreen.p Quickdraw.p 

Resources.p Scrap.p SCSIIntf.p 

SegLoad.p Sound.p StandardFile.p 

TextEdit.p Toollntf.p ToolUtils.p 

Types.p Videolntf.p Windows.p 


142 


Do not redeclare a type that is in one of the built-in intefaces. If you redeclare one of those types 
and try to call a Toolbox routine that requires an argument of that type, THINK Pascal gives you the 




Using Predefined Routines 


11 


error “Type incompatibility between an actual and formal value parameter.” You get this error even 
if you redeclare the type exactly as it is in the built-in interface. For example, this code will give 
you an error: 

program test; 
type 

rect = record 

top, left, bottom, right: integer 

end; 

var 

r: rect; 

begin 

SetRect(r, 10, 5, 200, 100); 

end. 

These interfaces are not built into THINK Pascal. If you use them, you must include them in your 
project and your unit’s uses clause. 


ADSP.p 

AIFF.p 

Aliases.p 

AppleEvents.p 

AppleTalk.p 

Balloons.p 

CommResources.p 

Connections.p 

ConnectionTools.p 

CRMSerialDevices.p 

CTBUtilities. p 

DatabaseAccess.p 

DeskBus.p 

Disks.p 

Editions.p 

ENET.p 

EPPC.p 

FileTransfers.p 

FileTransferTools. p 

Finder.p 

FixMath.p 

Folders.p 

Graf3D.p 

HyperXCmd.p 

Icons. p 

Language.p 

MIDI.p 

Notification.p 

Objlntf.p 

Palettes.p 

PasLiblntf.p 

Picker.p 

PictUtil.p 

Power. p 

PPCToolBox.p 

Printing.p 

PrintTraps.p 

Processes .p 

Retrace.p 

ROMDefs.p 

SANE.p 

Script.p 

SCSI .p 

Serial.p 

ShutDown.p 

Slots. p 

Sound.p 

Soundlnput.p 

Start. p 

Strings.p 

SysEqu.p 

Terminals.p 

TerminalTools. p 

Timer. p 

Traps.p 

Video.p 



For each of the built-in interfaces, there is a dummy interface File that contains no definitions. These 
make porting from other development systems easier, since you don’t need to modify a unit that 
includes one of these interfaces in its uses clause. 

Calling QuickDraw routines 

The standard QuickDraw routines described in Inside Macintosh /and the color QuickDraw rou¬ 
tines described in Inside Macintosh Kare predefined in THINK Pascal. You don’t need to do 
anything special to use them. 


143 




THINK Pascal User Manual 


THINK Pascal lets you use an alternate parameter list for the QuickDraw graphics operations on 
Rects, RoundRects, Ovals and Arcs. Instead of using a temporary Rect variable, you can supply the 
rectangle coordinates in the parameter list. So you can replace this: 

var 

r:rect; 

begin 

SetRect (r, left, top, right, bottom); 

FillRect (r, dkGray); 

end; 

with this: 

FillRect (top, left, bottom, right, dkGray); 

Note: The order of the arguments to SetRect is different from the order of the 
arguments to the QuickDraw routines. The alternate parameter list uses the same 
order as the Rect record declaration. 

You can use the alternate parameter list with these 20 procedures: 

EraseRect EraseRoundRect EraseOval EraseArc 

FillRect FillRoundRect FillOval FillArc 

FrameRect FrameRoundRect FrameOval FrameArc 

InvertRect InvertRoundRect InvertOval InvertArc 

PaintRect PaintRoundRect PaintOval PaintArc 

The function GetMouse, which usually takes a point as a parameter, can also take two parameters: 

procedure GetMouse(var h : integer; var v : integer); 

Calling AppleTalk routines 

If your application uses AppleTalk routines, you should be aware that there are now two versions 
of AppleTalk. Apple calls the old version (described in Inside Macintosh II) the alternate set. The 
new version, described in Inside Macintosh V t is called the preferred set. You’ll use a different 
library depending on which version of AppleTalk your application uses. 

To use... use this Interface file... and this library... 

preferred AppleTalk AppleTalk, p nAppleTalk. lib 

alternate AppleTalk AppleTalk.p ABPackage. lib 


144 



Using Predefined Routines 


11 


Calling Printing Manager routines 

There are two ways to use the Print Manager. If you want your project to run under System 4.1 or 
earlier, use the interface file Printing. p and include the library PrintCa 11s . lib. This way, 
calls to Print Manager routines use glue routines or the printing traps if they exist. If your program 
runs only on later systems, you should use the interface file PrintTraps. p so all calls to the Print 
Manager routines use the traps directly. 

If your program require... use this interface file... and this library... 

any System/Finder version Printing, p PrintCalls. lib 

System Tools 5.0 or later PrintTraps. p none 

Note: System Tools 5.0 consists of System 4.2 and Finder 6.0. To find out what 
System version your program is running under, use the Gestalt Manager, 
described in Inside Macintosh VI, Chapter 3, “Compatibility Guidelines,” or 
SysEnvirons, described in Inside Macintosh V, Chapter 1, “Compatibility 
Guidelines.” 

Calling SANE routines 

THINK Pascal lets you choose whether to generate code for the MC68881 or MC68882 floating 
point unit. If you use the 68881/68882 option, and you use SANE, you need to use a special version 
of the SANE library. 

If you... use this interface file... and this library... 

don’t use the 68881/68882 option SANE . p SANELib. lib 

use the 68881/68882 option SANE. p SANELib881. lib 

Calling Time Manager routines 

The debugging routines built into THINK Pascal take up so much time that Time Manager tasks 
may not run often enough when you choose a small interval. In fact, your application may crash 
when you’re running under the environment. 

If you’re running your application in the THINK Pascal environment, you should schedule tasks to 
be executed after more than 25 milliseconds. That is, the count parameter to the procedure 
Prime Time should be greater than 25. When you build your application, you can schedule Time 
Manager tasks to be executed at any interval. 

Note: Twenty-five milliseconds is an approximation. Depending on the kind of 
Macintosh you’re running on, you may be able to use a smaller interval or need to 
use a larger interval. 

To learn more about the Time Manager, see Inside Macintosh IV, Chapter 32, “The Time Manager.” 


145 





Building Projects 



Introduction 

You can write applications, desk accessories, device drivers, and code resources in THINK Pascal. 
This chapter tells you how to build the different kinds of projects. 

What you should know 

You should know how to use THINK Pascal. You should know how to create a project and how to 
add files and libraries to a project. You should know how to run your program in the THINK Pascal 
environment. If you don’t know how to do these things, go back to Chapter 7, “Working with 
Projects,” and to Chapter 8, “Running Programs.” 

If you want to write Macintosh applications, you should know about the resources that make up an 
application: menus, window templates, dialog manager, control templates, etc. You should know 
how to build these resources with a resource editor like ResEdit or with a resource compiler like 
SARez. To learn about resources read Inside Macintosh I, Chapter 5, “The Resource Manager,” and 
Inside Macintosh VI, Chapter 13, “The Resource Manager.” Other chapters in Inside Macintosh 
discuss different kinds of resources. 

If you want to write desk accessories or device drivers, you should be familiar with the mechanics 
of DRVR resources. These are a bit more complicated than other resources. See Inside Macintosh I, 
Chapter 14, “The Desk Manager” and Inside Macintosh II, Chapter 6, “The Device Manager” to 
learn about DRVR resources. 

If you want to build other kinds of resources (iNlTs, WDEFs, XCMDs, cdevs, etc.) see “Building 
Code Resources” later in this chapter. 

To learn how to call Macintosh Toolbox routines from THINK Pascal, read Chapter 11, “Using 
Predefined Routines.” 

Topics covered In this chapter 

• Setting the project type 

• Using resource files 

• Building applications 

• Building desk accessories and device drivers 

• Building code resources 

• Putting it together 



THINK Pascal User Manual 


Setting the Project Type 

Before you begin working on a project, you set the project type to let THINK Pascal know how to 
build your program into a finished file. To set the project type, choose the Set Project Type... 
command from the Project menu. You’ll see this dialog box: 



JO 

Desk Accessory 



Driver 


E 

Code Resource 


i— File Information 
Type: 


flPPL 


Creator: 


???? 


^ Bundle Bit 
□ Far Code 


Resource Information 
Name: i 


Type: { j III: j j attributes: ||| j 

□ MullF-Segment 

2 - 

Seyrneni Type: I 


□ Cut tom Header 


.2 

. ! 


Oriuer information 
Hoyt: Qj j Delay: j 

Mask: Qf ] 




OK 


3 


[ Cancel ] 


To set the type of project, click on one of the four icons along the left of the dialog. Depending on 
the icon you choose, the gray parts of the dialog may become active. 

Note: Changing the project type doesn’t mean that your program will behave dif¬ 
ferently. For instance, if you change the project type from Application to Desk 
Accessory, your application won’t turn into a desk accessory automatically. There 
are different rules for writing the different kinds of projects. 

The rest of this chapter goes into detail about the different kinds of projects. For all types of pro¬ 
jects, though, you’ll need to fill in the file information section. This section lets the Finder know 
what kind of file you’re creating and how to display it on the desktop. 

The file type lets the Finder know what kind of file it is. For applications, the type is APPL. Other 
kinds of files have other types. Text files, for instance, have the type TEXT. The creator field identi¬ 
fies the application that created the file. If the file type is APPL, the creator is the unique four 
character signature of the application. 

If you check the Bundle bit check box, THINK Pascal will set the bundle bit in the file’s Finder in¬ 
formation record. The Bundle bit lets the Finder know that your application has a BNDL resource 
and that it has its own icon. 


148 






































Building Projects 12 


For more information on how the Finder uses the BNDL resource, see Chapter 7 of the Resource 
Utilities Manual. To learn more about the File type, the file creator, and the bundle bit, see Inside 
Macintosh III, Chapter 1, “The Finder Interface,” and Inside Macintosh VI, Chapter 9, “The Finder 
Interface. ” 

Using Resource Files 

When you launch an application from the Finder, it looks in the resource fork of the application for 
its resources. When you run your program in the THINK Pascal environment, it’s not quite an 
application yet, so your program needs to know where to find its resources. 

The Resources section of the Run Options... command in the Run menu lets you specify where 
your program should expect its resources. When you choose the Run Options... command, you’ll 
see this dialog box: 


Run-time Enuironment Settings 


Resources 

□ Use resource file: 

for resources used by the project. 

Tent 

Tent Ulindoui saues 5000 characters 

□ Echo to the printer 

Ulindoui 

□ Echo to the file: 


Hello world, x » 811.79. 


Monaco ▼ | 

_9_tJ 


Memory 


Stack size:| 16 (kilobytes | 

It J1 

Zone size:| 128 {kilobytes 

{ Cancel ] 


When you click in the Use resource file: check box, you’ll see a standard file dialog. Choose the file 
that contains the resources for your program. The name of the file you select appears in the box. 


Note: THE RESOURCE FILE MUST BE IN THE SAME FOLDER AS THE PROJECT. 

When you run your program in the THINK Pascal environment, THINK Pascal opens your resource 
file so you can access your resources. When you’re ready to build your project into a stand-alone 
application, THINK Pascal copies the resources in your project’s resource file into the final 
application file. 


149 








THINK Pascal User Manual 


You can use ResEdit or SARez (in the THINK Pascal 4.0 Utilities folder) to create 
resource files. To learn more about SARez, see the Chapter 22, “Using SARez.” To learn more about 
ResEdit, see ResEdit 2.1 Reference (Addison-Wesley) by Apple Computer, Inc. 

By convention, files that contain resources to be used as part of a project end in . rsrc. 

Building Applications 

THINK Pascal is set up to build applications by default. When you set the project type, all you need 
to do is give your application a creator. If the application you’re writing is a one-shot — it doesn’t 
need its own icons, and it doesn’t create its own files — you can just take the defaults and not 
bother with the Set Project Type... dialog. 

Toolbox Initialization 

When your program starts up, THINK Pascal inserts calls to the following Toolbox initialization 
routines for you: 

InitGraf 
InitFonts 
InitWindows 
InitMenus 
TEInit 

If you call these routines while your program is running in the THINK Pascal environment, nothing 
happens. If you leave them in your final application, your application will crash when it starts. 

If you’re porting code from other development systems, and that code includes these initialization 
routines, you can use the { $1-} compiler directive immediately after the program statement to 
disable the automatic initialization. To learn more about this and other compiler directives, see 
Chapter 15. 

Text and Drawing windows 

When your program is running in the THINK Pascal environment, you can use the Text and 
Drawing commands in the Windows menu to display the Text and Drawing windows. If your 
program uses these windows, you’ll need to use the following procedures to work with the Text 
and Drawing windows in a standalone application: 

ShowText SetTextRect 

ShowDrawing SetDrawingRect 

HideAll 

See section 10 of Chapter 17 to learn more about these procedures. 

Running the project 

When you use one of the execution commands— Go, Step Into, Step Over, Step Out, Go-Go, or 
Step-Step —in the Run menu, THINK Pascal runs your program in an environment that resembles 
the standard Macintosh software environment. 


InitDialogs 
SetApplLimit 
MaxApplZone 
MoreMasters (10 times) 


150 




Building Projects 12 


To learn more about running your project in the THINK Pascal environment, see Chapter 8. 

Building applications with large jump tables 

If you're building a large application, especially one that uses the THINK Class Library or MacApp, 
its jump table can grow large quickly. The jump table contains entries for the following: 

• Every class 

• Every method 

• Every routine called by a routine in another segment 

• Every routine that you take the address of. 

If you need a large jump table, check the “Far Code” option. It lets a jump table grow to 256K, since 
it uses 32-bit absolute addresses instead of 16-bit relative addresses. Your application will be about 
6% larger because of the longer addresses. If the “Far Code” option is off, your jump table can be 
only 32K. 

Far Code lets you make larger applications with more space for your jump table since it handles 
addresses into the jump table differently. When this option is off, addresses into the jump table are 
given as offsets from A5. In the MC68000 family, register-relative offsets must be 16-bits long, so the 
jump table can contain only 32K. When this option is on, addresses to the jump table are absolute 
addresses and can be 32-bits long. THINK Pascal includes code in your application that adds the 
value of A5 to these absolute addresses before your code runs. 

Note; If you’re using Object Pascal and the “Far Code” option is on, the entry 
«%_MethTables» can be up to 64K., instead of just 32K. However, because of 
this extended limit, you must put «%_MethTables» in its own segment 
whenever the “Far Code” option is on. For more information, see “Segmenting a 
Project” in Chapter 7, “Working with Projects.” 

If the “Far Code” option is on and your application contains libraries that were compiled with the 
option off, put those libraries together in their own segment (or segments). THINK Places places 
the jump table entries for those libraries in first 32K of the jump table. If the libraries are grouped 
together, THINK Pascal won’t waste space in the First 32K by placing in it entries that can be 
elsewhere. Also, if one of those libraries calls a function in one of your files, put that file in the 
same segment as those libraries. 

Building the application 

When you’re finished debugging your application, use the Build Application... command in the 
Project menu to create your application file. Read the section “Putting it Together” at the end of 
this chapter to learn how THINK Pascal creates your final application. 

Building Desk Accessories and Device Drivers 

Desk accessories and device drivers are structurally identical; they’re both drivers. According to 
Inside Macintosh , drivers don’t behave like applications and have a different internal structure. In 
this section, the word driver means either a desk accessory or a device driver. 


151 



THINK Pascal User Manual 


This section won’t teach you how to write a desk accessory or a device driver from scratch. To 
learn how to write these, read Inside Macintosh /, Chapter 14, “The Desk Manager,” Inside 
Macintosh n, Chapter 6, “The Device Manager,” and Inside Macintosh V, Chapter 23, “The Device 
Manager.” 

Setting the project type 

Set the project type before you start working on a driver. If you set the project type after you’ve 
started compiling code, you’ll have to recompile your source files. 

Choose Set Project Type... from the Project menu. When the project type dialog appears, click 
on either the Desk Accessory icon or the Device Driver icon. 

The Desk Accessory dialog presets the file type and creator so the resulting file will be a Font/DA 
Mover file. The ID is set to 12. The Font/DA Mover renumbers it when you install it in your System. 
You shouldn’t need to change the ID number. All that’s left to do is to name the desk accessory and 
write the code. By convention, desk accessory names begin with a NUL (chr (0)). THINK Pascal 
provides it for you automatically. 



152 











Building Projects 12 


The Device Driver dialog is a little bit different Device driver names begin with a period. If you 
don’t provide one in the Name field, THINK Pascal automatically provides one for you. 



Application 



Desk Accessory 



Code Resource 


File Information 
Type: 


???? 


Creator: 


???? 


□ Bundle Bit 

□ far Coda 


Resource Information 
Name: 


Type: 


ORUR 


ID: 


Attributes: 


00 


□ Multi-Segment 

Secjrrioril Type: j j 


□ Custom Hoarier 


i— Driuer Information 


Flags: |§j 


4F00 


Delay: 


Mask: ||| 


0000 


£ 


OK 


[ Cancer 


Note that the Flags field of the Driver Information section is different for desk accessories and 
device drivers. Later on you’ll see what these two fields mean. 

Before you start working on your driver, you need to do one more thing. You need to remove the 
default Runtime. lib library and replace it with the special DRVRRuntime. lib library. This li¬ 
brary is like Runtime .lib except that it uses register A4 to access globals, and it does not contain 
the Pascal I/O routines. (This means that you can’t use writeln in a desk accessory, for instance.) 

Note; To change the library, hold down the Option key as you double-click on 
the library name. THINK Pascal displays a standard file dialog that lets you choose 
the replacement file. 

Both device drivers and desk accessories can have more than one segment, just like applications. 
Just click on the Multi-Segment check box. You can learn more about multi-segment drivers below, 
but read how a driver works first. For more information on segmentation, see “Segmenting a 
Project” in Chapter 7. 

Note: If your driver uses Object Pascal, you must check the Multi-Segment option 
even if your driver contains only one segment. 

How drivers work 

The Device Manager expects drivers to have five entry points and to be written in assembly lan¬ 
guage. When the Device Manager calls a driver written in THINK Pascal, a short assembly-language 


153 










THINK Pascal User Manual 


stub translates the Device Manager’s request into a call to a Pascal function called main. THINK 
Pascal automatically places the driver glue at the beginning of your driver. 

The THINK Pascal driver glue also does two things designed to make writing a driver easier. First, it 
sets up a data area so that your driver can have its own global variables. Second, it figures out the 
proper way to return control to the Device Manager automatically. You’ll learn more about these 
services later in this section. 

How to write a driver In THINK Pascal 

To write a driver in THINK Pascal, you have to follow two rules. The first rule is that a driver must 
consist only of units. It may not have a file with a main program. The second rule is that a driver 
must have a function called main defined in one of its units, and that function must also appear in 
its interface section. This is the skeleton for a THINK Pascal driver: 

unit MyDeskAccessory; 

interface 

function main(devCtlEnt: DCtlPtr; paramBlock: ParmBlkPtr; 
sel: integer): integer; 


implementation 

function main; 
begin 

case sel of 

0: { Open } 

1: { Prime } 

2: { Control } 

3: { Status } 

4: { Close } 

end 

end; 

end. 

The function main takes three arguments that let you know how your driver is being called. 

The first argument, devCtlEnt, is a pointer to the driver’s device control entry. This is the value 
that is passed in register A1 to the assembly language entry point of the driver. 

The second argument, paramBlock, is a pointer to an I/O parameter block. This is the value that 
is passed in register AO to the assembly language entry point of the driver. 

The last argument, sel, is a selector that specifies which entry point actually received the call. Use 
the value of sel to dispatch control to the appropriate routine. 


154 




Building Projects 12 


Getting the event record pointer from the parameter block 

According to Inside Macintosh /, Chapter 14, “The Desk Manager," the csCode field of the 
paramBlock passed to your driver specifies what kind of action your driver should take. When 
paramBlock'' . csCode = accEvent, the csParam field of paramBlock contains a pointer to 
an EventRecord. 

The csParam field is defined as an array of integers, so you’d have to cast the first two integers of 
the array into the pointer to the event record. It’s much easier to use the ioMisc field, which is de¬ 
fined in another variant of ParamBlockRec, because it points to the right place in memory, and 
it’s already a pointer. 

var 

EventP : A EventRecord; 

EventP := Pointer (paramBlock''. ioMisc) ; 

Global data In drivers 

You can declare global and static variables in drivers. The THINK Pascal driver glue allocates the 
space for the globals in the heap before it calls main to implement the Open entry. The glue re¬ 
leases the memory when the driver returns from a Close call. (There is a way to keep the global 
data area allocated after a Close; see “Returning from a driver” below.) 

Note; All of the globals in your driver are guaranteed to be set to zero on the first 
Open call. 

Macintosh applications use register A5 to access their globals. Since drivers co-exist with running 
applications, they can’t use register A5 to access their globals. Instead, drivers use register A4. 

The THINK Pascal driver glue stores a handle to the dynamically allocated data area in the 
dCtlStorage field of the driver’s device control entry. This handle is dereferenced into address 
register A4 and locked before each call to main. Your Open routine must check whether the data 
area was allocated successfully. If it was not, the dCtlStorage field will be 0, and your driver 
should display some error message (without using any globals!) and close itself. Your code might 
look like this: 

if devCtlEnt''. dCtlStorage = nil then 
begin 

SysBeep(5); 
exit(main); 

end; 

The data area remains locked between calls to your driver. If you like, you can unlock it yourself 
before returning. If you unlock the data area, though, make sure that you don’t rely on the address 
of any data item staying the same between calls. Also, make sure that the data area doesn’t contain 
any objects, such as windows, that the Toolbox assumes will not move. 


155 



THINK Pascal User Manual 


Using driver globals In callback and trap Intercept routines 

The THINK Pascal driver glue sets up register A4 for you whenever your driver is called from 
main. If your driver defines callback routines, trap intercept routines, or other functions that might 
be called when the value of A4 is in doubt, you have to save A4 where your routines can find it. 

The special library for drivers, DRVRRuntime. lib, contains the procedures RememberA4, 
SetUpA4 and RestoreA4 that take care of saving, setting, and restoring A4 for you. 

Your main routine must call RememberA4 before any calls to SetUpA4. All calls to SetUpA4 and 
RememberA4 must be from the same segment that contains main. This means that the file that 
contains main, DRVRRuntime. lib, and any files that contain calls to SetUpA4 and RestoreA4 
must be in the same segment. 

Suppose your driver calls ModalDialog with a f ilterProc. Since you’re not sure if the value of 
A4 will be correct when ModalDialog calls your f ilterProc, you need to set A4 to the proper 
value. Your f ilterProc would look like this: 

function MyFilterProc(dp : DialogPtr; var event: EventRecord; 

var item : integer) : Boolean; 

var 

result : Boolean; 

begin 

SetUpA4; { main must call RememberA4 first! } 

MyFilterProc := result; 

RestoreA4; 

end; 

Your main routine would look like this: 
function main; 
begin 

RememberA4; { Stash A4 where SetUpA4 knows } 

{ where to find it } 

case sel of 

0: { Open } 

1: { Prime } 

2: { Control } 

3: { Status } 

4: { Close } 

end 

end; 

Use the same technique for trap intercept routines that need access to a driver’s globals. Of course, 
if your callback or trap intercept routine doesn’t use driver globals, you don’t need to set up and 
restore A4. 


156 





Building Projects 12 


Using THINK Pascal libraries In drivers 

You can use libraries in drivers as long as the libraries don’t reference global variables accessed 
through register A5. The special version of the run-time library for drivers, DRVRRuntime. lib, 
was built so it references its globals from A4. 

The QuickDraw globals aren’t in DRVRRuntime. lib. You can access the real QuickDraw globals 
in a driver from assembly language by observing that 0 (A5) holds the address of the last of the 
QuickDraw globals, thePort. The remaining QuickDraw globals are at descending addresses 
from thePort; refer to Inside Macintosh I, Chapter 6, “QuickDraw” for more information. The 
value of A5 is stored in the low-memory global CurrentAS. 

Note; The only reason most people need to use the QuickDraw globals from a 
driver is to get the bounds of screenBits. A common trick to get this informa¬ 
tion from a driver is to create a new Graf Port. The default portBits is the 
same as screenBits. Don’t forget to get rid of the port once you have what you 
want. 

You can use most of the libraries supplied with THINK Pascal (PrintCalls, nAppleTalk, 
FixMath, Graf 3D, etc) in your drivers. You can’t use jlRuntime. lib or Runtime, lib. 

Using Imported libraries In drivers 

THINK Pascal honors most initializations from imported THINK C libraries and MPW . o files. For 
example, if a THINK C library contained this initialization: 

char myString[] = "\psome string"; 

the value of my St ring would be " \psome string" when the library is loaded. 

However, in drivers, THINK Pascal does not honor initializations from imported libraries that set a 
variable to be a pointer to a function or a pointer to another variable (that is, initializations that re¬ 
quire runtime relocations). For example, THINK Pascal would not honor this initialization in a 
THINK C library: 

static ProcPtr myHook = &myFunction; 

Setting the fields of a driver’s header 

A driver begins with a header that contains several flags and other data items (some of which apply 
only to desk accessories). When the driver is opened, the Device Manager copies these fields to the 
device control entry before the Open entry point is called. After that, the device header is not used. 
The fields in the driver are used only to initialize the fields in the device control entry. 


157 



THINK Pascal User Manual 


THINK Pascal lets you set the drvrFlags and the drvrEMask fields in the Set Project Type... 
dialog.Use the Flag and Mask pop-up menus to set the flags you want. 


Application 


Code Resource 


— File Information —-—-- 

_ _ □ Bundle Bit 

Type: |PF1L Creator: |PMPU □ Far code 

— Resource Information- 

Name:_ 

Type: |PBUB | IP: 112 | Attributes: ggj [piT 


□ Multi-Segment 

Segment Type: | 


□ Cut tom Ht>od»>r 


Priuer Information 


Flags: 


v'keyPown 

v^autoKey 

v/updateEut 

v'actiuateEut 


P4PP Pelay: P 


These two fields are copied to the dCtlFLags and dCtlEMask fields of the device control entry. 

These are the default settings for desk accessories. The symbols dReadEnable, dWritEnable, 
etc refer to bits of the high byte of the drvrFlags. DReadEnable is bit 0, dNeedLock is bit 6. 
When you set the flag yourself, leave the other bits clear. 


Field 

dCtlFlags 


dCtlDelay 

dCtlEMask 

dCtlMenu 


Value 

$0400 

dReadEnable 0 

dWritEnable 0 

dCtlEnable 1 

dStatEnable 0 

dNeedGoodbye 0 

dNeedTime 0 

dNeedLock 0 

N/A because dNeedTime = 0 

0x016A (mouseDown, keyDown, autoKey, 

update, activate) 

0 


158 













Building Projects 


12 


These are the default settings for device drivers: 

Field Value 

dCtlFlags $4F00 

dReadEnable 1 

dWritEnable 1 

dCtlEnable 1 

dStatEnable 1 

dNeedGoodbye 0 

dNeedTime 0 

dNeedLock 1 

dCtlDelay N/A because dNeedTime = 0 

dCtlEMask N/A (desk accessories only) 

dCtlMenu N/A (desk accessories only) 

THINK Pascal copies the fields from the driver’s header to the device control entry on every Open 
call. If you want to change the settings of the driver headers on the fly, you’ll need to set them on 
every Open call. 

Opening an open driver 

The Open entry point of a driver (main’s third argument = 0) may be called even if the driver is al¬ 
ready open. This happens, for example, when the user selects the name of a desk accessory that’s 
already on the screen. The driver should check to see if it is already open to avoid repeating its 
initialization sequence. 

Since THINK Pascal guarantees that all your driver globals will be set to zero, you can use a global 
flag to determine whether your driver’s been opened before. Your Open routine might look like 
this: 

procedure doOpen; 
begin 

{ AlreadyOpen is a boolean global. } 
if AlreadyOpen then 
exit(doOpen); 

AlreadyOpen := TRUE; 

{ Initialization code } 

end; 

How to return from a driver 

If your Open routine was successful, return 0. If the Open routine fails, return a negative result and 
the driver will not be opened. 

Return 0 from Close if it was successful. If your Close routine returns closeErr (-24) the driver 
won’t be closed. If you return a 1, the THINK Pascal driver glue will preserve the dCtlStorage 
field of the device control entry. This way you can keep your driver globals around until your 

159 



THINK Pascal User Manual 


driver is reopened. (The driver glue will make it seem as though your Close routine returned 0, 
meaning the Close was successful.) 

Note: Returning negative values from Open and Close to prevent opening or 
closing works only on 128K and later ROMs. 

Return 1 from asynchronous calls to Prime, Control, and Status routines if the request could 
not be completed right away. This result code will be stored in the ioResult field of the I/O 
parameter block, but 0 (no error) will be returned to the Device Manager. 

The jlODone problem 

THINK Pascal always returns from a driver correctly. In other development systems, it’s not so easy. 
Read this section if you want to learn about this problem. Since you don’t have to worry about it, 
you might want to skip this section. 

One of the trickiest aspects of returning from a driver is deciding whether to return directly to the 
Device Manager (via an RTS instruction) or whether to jump to jlODone. This is a complex issue, 
and many existing desk accessories do it wrong (though, fortuitously, they manage to work 
anyway). 

Associated with each driver is an I/O queue, which is a list of I/O parameter blocks waiting for ser¬ 
vice from the driver. Calls made to a driver fall into one of two categories: queued , meaning that 
the I/O parameter block passed as an argument to the call is in the driver’s queue; and immediate , 
meaning that it is not. In the immediate case, the queue may even be (and in fact usually is) empty. 

All Open and Close calls are immediate. All Control calls made to desk accessories are imme¬ 
diate, except for the “goodbye kiss” (csCode=-l) issued to desk accessories that have requested 
to be notified when the current application exits out from under them. Other calls may be queued 
or immediate. 

The rules for returning from a driver are: The driver should return directly to the Device Manager 
from all immediate calls. It should also return directly to the Device Manager from queued calls re¬ 
questing asynchronous I/O that could not be completed right away. Finally, it should jump to 
jlODone from queued calls if the driver completed the request (or if there was an error). 

It is incorrect to violate these rules; in particular, it is incorrect to jump to j IODone to return from 
an immediate call. jlODone will attempt to examine the driver’s I/O queue, and since the queue is 
usually empty it will end up examining low-memory locations beginning at $ 0 0 0 0 . Apparently, 
these locations somehow look enough like an I/O parameter block to satisfy the Device Manager, 
but this is clearly an unsafe situation. 

Just to make things difficult, when returning from Prime, Control, and Status calls, it is 
jlODone that unlocks the driver’s code and its device control entry so they won’t form islands in 
the heap between calls to the driver (unless, of course, the driver has requested that they remain 
locked). So the author of a desk accessory, for instance, has to make a difficult decision — to return 
directly to the Device Manager, leaving the driver’s code and its device control entry locked and 


160 



Building Projects 12 


potentially interfering with the host application; or to violate the rules and jump to jlODone. Most 
desk accessories seem to take the latter route. 

THINK Pascal avoids this dilemma. When a driver written in THINK Pascal returns from main, the 
decision whether to call jlODone is made automatically (and correctly). For Prime, Control, 
and Status calls, if the decision is made to return directly to the Device Manager, and the driver 
has not requested that its code and device control entry remain locked, they are unlocked. 

Multi-Segment drivers 

If the Multi-Segment option is on, drivers can contain multiple segments. The Type field in the Set 
Project Type... dialog lets you specify the resource type of the owning resource. THINK Pascal 
gives the owned resources the type DCOD. 

The ID field in the Set Project Type... lets you choose the resource ID for the owning resource. 
THINK Pascal ensures that the resource ID for the owning resource is between 0 to 63. If you enter 
a number outside that range, you’ll see an error message. THINK Pascal numbers the owned 
resources for you. 

The Attributes field in the Set Project Type... dialog lets you set up the resource attributes of the 
owning resource. To set the resource attributes for an owned resource, double click on the 
segment’s summary line in the project window’s segment view, and use the Attributes field in the 
dialog that appears. For more information, see “Naming segments” in Chapter 7, “Working with 
Projects.” 

As with applications, segments are loaded automatically as they are called. In addition, all loaded 
segments are unloaded automatically upon return to the Device Manager after each call, unless the 
dNeedLock bit is set in the driver’s device control entry. 

To make sure that there is enough memory for a multi-segment driver, you may want to “preflight” 
it. “Preflighting” means that you load all the segments to see if there’s enough memory for them. If 
there’s enough memory, you can continue executing. Otherwise, you exit gracefully. 

To preflight your driver, you must first name your segments. To learn how, see “Segmenting a 
Project” in Chapter 7. Then, use the GetNamedResource function to load in each segment like 
this*. 


var 

h: Handle; 

begin 

h := GetNamedResource ('DCOD', ' segment-name '); 
if h = nil then 
{ exit gracefully } 

end; 

Be sure to check the return value of GetNamedResource. If it’s nil, you don’t have enough 
memory for your driver, and you should exit gracefully. 


l6l 



THINK Pascal User Manual 


Note: Don’t use LoadSeg. It loads CODE resources. Driver segments are DCOD 
resources. 

You can unload driver segments manually with this function: 

procedure UnloadA4Seg(theProcPtr: ProcPtr); 

This function works just like UnloadSeg does in applications. To unload one segment, call 
UnloadA4Seg with the address of a routine in that segment; for example, 

UnloadA4Seg (@foo). To unload all segments at once, call UnloadA4Seg with nil; that is, 
UnloadA4Seg (nil). 

Note: Do not use UnloadSeg instead of UnloadA4Seg by mistake! 

Read “Arranging Files in the Project” in Chapter 7 to learn how to break up your project into 
segments. 

Note: If your driver uses Object Pascal, you must check the Multi-Segment option 
even if your driver contains only one segment. 

Running desk accessories 

You can’t run a desk accessory with one of the execution commands in the Run menu because 
desk accessories aren’t real applications. (They don’t even have a main program!) To run a desk 
accessory, use the special DA Shell program that’s included in your THINK Pascal package. 

The DA Shell is a small program that simulates an environment for your desk accessory. It takes 
advantage of the fact that a desk accessory is a unit and that it’s called through the function main. 
The DA Shell creates a fake device control entry and a fake I/O parameter block for your main 
function. 

To use the DA Shell: 

• Make a backup copy of the DA Shell file 

• Create a new project with the default libraries 

• Add your desk accessory units to the project 

• Add the DA Shell File to the project 

• In the DA Shell file, put your desk accessory’s unit name in the uses clause 

To run your desk accessory, choose one of the execution commands — Go, Step Into, Step Over, 
Step Out, Go-Go, and Step-Step — from the Run menu, then choose Sample DA from the Apple 
menu. When you use the DA Shell, you can use any of THINK Pascal’s debugging tools to debug 
your desk accessory. 

Desk accessories that work in the DA Shell should work properly as real desk accessories. But 
since the DA Shell is a simulated environment, you should be aware of several things: 

• When your desk accessory is running in the DA Shell, events in your windows look like 
inContent. When you run your desk accessory as a real desk accessory, these events will be 


162 



Building Projects 12 


inSysWindow. At least while you’re debugging, your desk accessory should treat inContent 
hits as inSysWindow hits. 

• If your desk accessory uses owned resources, calculate the unit number as 

abs (dCtlRefNum) -1. In a real desk accessory dCtlRefNum is guaranteed to be negative, so 
the unit name is calculated as -dCtlRefNum-1, but in the DA Shell it’s dCtlRefNum-1. 

• In the DA Shell, your desk accessory will get a goodbye kiss synchronously (immediately). As 
a real desk accessory, it gets it asynchronously. 

If you’re writing a multi-segment desk accessory, and you want to use the DA Shell, you may 
need to define dummy versions of the A4 routines like this: 

unit DummyA4World; 
interface 

procedure SetUpA4; 
procedure RestoreA4; 

UnloadA4Seg(pPtr: ProcPtr); 

implementation 

procedure SetUpA4; 

begin 

end; 

procedure RestoreA4; 

begin 

end; 

procedure UnloadA4Seg(pPtr: ProcPtr); 

begin 

UnloadSeg(pPtr) 

end; 

end. 

Just add this unit to your project after your libraries. You don’t need to put the unit’s name in a 
uses clause since the compiler will treat the procedure names as externals and resolve them at 
link time. 

Building Code Resources 

You can use THINK Pascal to write pure code resources. Code resources don’t have the complex 
structure of drivers. They simply contain code to be called at the entry point, the function or 
procedure main. 

You might want to write code resources for several reasons. You might want to write a window 
definition function (WDEF) that you can use in several other programs, or you might want to write 
an INIT to run at startup. You may define your own code resource types to make a function 


163 




THINK Pascal User Manual 


you’ve written i n THINK Pascal available to a program written i n another language. The “client” 
program simply loads the resource and calls it at its beginning. 

This section tells you how to build code resources in THINK Pascal. The specific formats and call¬ 
ing sequences for code resources are given in the various volumes and chapters of Inside 
Macintosh. This list will help you get started. 


To learn how to build a... 

ADBS resource 
CDEF resource 
cdev resource 
FKEY resource 
I NIT resource 

LDEF resource 
MBDF resource 
MDEF resource 

WDEF resource 
XCMD resource 
XFCN resource 


Read Inside Macintosh ... 

Volume V, Chapter 20, “The Apple Desktop Bus” 
Volume I, Chapter 10, “The Control Manager” 
Volume V, Chapter 18, “The Control Panel” 
Macintosh Technical Note #3 (also see below) 
Volume IV, Chapter 29, “The System Resource File” 
Volume V, Chapter 19, “The Start Manager” 

Volume IV, Chapter 30, “The List Manager Package” 
Volume V, Chapter 13, “The Menu Manager” 
Volume I, Chapter 11, “The Menu Manager” 

Volume V, Chapter 13, “The Menu Manager” 
Volume I, Chapter 9, “The Window Manager” 
HyperCard Script Language Guide , Appendix A 
HyperCard Script Language Guide , Appendix A 


Setting the project type 

Set the project type before you start working on a code resource. If you set the project type after 
you’ve started compiling code, you’ll have to recompile your source Files and reload your libraries. 
Choose Set Project Type... from the Project menu. When the dialog appears, click on the Code 
Resource icon. 


i— File Information 
Type: 


Application 


???? 


Creator: 


???? 


□ Bundle Bit 

□ Far Code 


i— Resource Information 
Name: 


Desk Accessory 

gj 

Driver 


Type: 


???? 


ID: 


^ Multi-Segment 
Segment Type: 


Rttributes: |g| [oo | 

□ Cutt»m Header 


CCOD 


1 . 

i Driuer Information 


| Flag*: Ff=j| j Delay: j 

Ill 0K 1 


j Mask: Q[ j 

l. 

: 

! f Cancel 


164 




















Building Projects 12 


Fill in the Type and ID of the code resource you’re building. If you like, you can give your code 
resource a name. 

Use the Attributes pop-up menu to set the resource attributes for your code resource. To learn 
about resource attributes, see Inside Macintosh /, Chapter 5, “The Resource Manager.” 

If the Multi-Segment option is checked, code resources can contain more than one segment and 
global data. The Segment Type Field lets you you specify the resource type of your code resource’s 
owned segments. For more information, see “Multi-segment code resources” later in this section. 

Note: If your code resource uses Object Pascal or global data, you must check the 
Multi-Segment option even if your driver contains only one segment. 

If you check the Custom Header check box, THINK Pascal doesn’t use the standard code resource 
header to start the resource. See “Code resource headers” later in this section. 

Before you start working on your code resource, you need to replace the default Runtime. lib 
library with the RSRCRuntime. lib library. This library is like Runtime .lib except it doesn’t 
contain the Pascal I/O routines. (This means that you can’t use writelnina code resource, for 
instance.) DRVRRuntime. lib and RSRCRuntime. lib differ slightly in how they handle the A4 
world. 

How to write a code resource In THINK Pascal 

To write a code resource in THINK Pascal you must follow some rules: 

• It must consist only of units. 

• It must not have a main program. 

• It must have a unit that contains a function or a procedure called main. 

• The main routine must appear in the interface section of its unit. 

The way you write your main routine depends on the kind of resource you’re writing. An FKEY, 
for example, is called by the Event Manager. It doesn’t have any arguments. You would define 
main like this: 

unit MyFKEY; 
interface 

procedure main; 

implementation 

procedure main; 

begin 

end; 

end. 


165 




THINK Pascal User Manual 


A WDEF resource is a custom window definition. The Window Manager calls main with several ar¬ 
guments and expects the window definition function to return a longint. This is how you would 
write main for a WDEF: 


function main 
begin 


(varCode: integer; theWindow: WindowPtr; 

message: integer; param: longint): longint; 


end; 


Global data In code resources 

Code resources can have global data only if the Multi-Segment option in the Set Project Type... 
dialog is on. Unlike drivers and applications, you can’t use global data if the Multi-Segment option 
is off. 


Note: Even if the Multi-Segment option is on, you can create a code resource with 
only one segment. It’s a multi-segment code resource with only one segment. 

For more information on writing multi-segment code resources, see “Multi-segment code 
resources” later in this section. 

Using THINK Pascal libraries In code resources 

You can use libraries in code resources as long as the libraries don’t reference global variables ac¬ 
cessed through register A5. The library RSRCRuntime. lib references its globals from A4 

The QuickDraw globals aren’t in RSRCRuntime. lib. You can access the real QuickDraw globals 
in a driver from assembly language by observing that 0 (A5) holds the address of the last of the 
QuickDraw globals, thePort. The remaining QuickDraw globals are at descending addresses 
from thePort; refer to Inside Macintosh L, Chapter 6, “QuickDraw” for more information. The 
value of A5 is stored in the low-memory global CurrentA5. 

Note: The only reason most people need to use the QuickDraw globals from a 
driver is to get the bounds of screenBits. A common trick to get this informa¬ 
tion from a code resource is to create a new Graf Port. The default portBits is 
the same as screenBits. Don’t forget to get rid of the port once you have what 
you want. 

You can use most of the libraries supplied with THINK Pascal (PrintCalls, nAppleTalk, 
FixMath, Graf 3D, etc) in your drivers. You can’t use ^.Runtime. lib or Runtime. lib. Also, 
you cannot use DRVRRuntime. lib in a multi-segment code resource. 


166 



Building Projects 12 


Using Imported libraries In code resources 

THINK Pascal honors most initializations from imported THINK C libraries and MPW . o files. For 
example, if a THINK C library contained this initialization: 

char myString[] = "\psome string”; 

the value of my St ring would be " \psome string” when the library is loaded. 

However, in drivers, THINK Pascal does not honor initializations from imported libraries that set a 
variable to be a pointer to a function or a pointer to another variable (that is, initializations that re¬ 
quire runtime relocations). For example, THINK Pascal would not honor this initialization in a 
THINK C library: 

static ProcPtr myHook = &myFunction; 

Locking code resources 

The Macintosh Toolbox takes care of locking and unlocking the standard code resources like 
WDEFs. When you write your own code resources, you can either let the caller take responsibility 
for locking and unlocking them, or you can have the code resource do it itself. 

When main is entered, the low memory global ToolScratch contains a pointer to your code 
resource. If you need to lock it, you would write main like this: 

procedure main; 

var 

pp: "Ptr; 
h: Handle; 


begin 

pp := Ptr($09CE); { ToolScratch } 

h := RecoverHandle (pp 7 ') ; 

HLock(h); 

HUnlock(h); 

end; 

Note: When the Toolbox uses an MDEF, it expects to find a certain value in 
ToolScratch. To write an MDEF, you’ll have to use a Custom Header, described 
below. 

If your code resource can be called reentrantly, don’t unlock it unconditionally when it returns. 
Instead, restore it to the same state of locked-ness it had on entry. 


167 



THINK Pascal User Manual 


Code resource headers 

When THINK Pascal creates a code resource it places this standard header at the beginning: 

Offset Contents 

0 BRA.S .+$10 (branch to header code) 

2 $0000 (unused) 

4 1 TYPE 1 (resource type) 

8 $000A (resource ID) 

10 ($A) $0000 (unused) 

12 ($C) $0000 (unused) 

14 ($E) $0000 (unused) 

The standard header code puts the address of your code resource in ToolScratch and then 
branches to your main routine. You can do anything you like with the unused words. 

If you check the Custom Header option in the Set Project Type... dialog, THINK Pascal does not 
generate this standard resource header. Instead, the file that contains main is guaranteed to be the 
first file in the code resource. 

You can use this feature for writing resources that require special headers like PDEFs. The file that 
contains main should be written in assembly language. See Chapter 13 to learn how to write 
routines in assembly language for use in THINK Pascal. 

Note: Multi-segment code resources must use THINK Pascal’s default header. If 
the Multi-Segment option is checked, the Custom Header option is dimmed. 

Multi-segment code resources 

If the Multi-Segment option is checked in the Set Project Type... dialog, code resources can 
global data and up to 31 segments. Read the section “Segmentation” earlier in this chapter to learn 
how to break up a project into different segments. 

The Type field in the Set Project Type... dialog lets you specify the resource type of the owning 
resource. To specify the resource type of the owned resources, use the Segment Type field. The 
Segment Type default is CCOD. 

The ID field in the Set Project Type... lets you choose the resource ID for the owning resource. 
THINK Pascal ensures that the resource ID for the owning resource is between 0 to 63. If you enter 
a number outside that range, you’ll see an error message. THINK Pascal numbers the owned 
resources for you. 

The Attributes field in the Set Project Type... dialog lets you set up the resource attributes of the 
owning resource. To set the resource attributes for an owned resource, double click on the 
segment’s summary line in the project window’s segment view, and use the Attributes field in the 
dialog that appears. For more information, see “Naming segments” in Chapter 7, “Working with 
Projects.” 


168 



Building Projects 


12 


The Custom Header option in the Set Project Type... is dimmed. Multi-segment code resources 
must use THINK Pascal’s default header. 

Before you start working on your code resource, you need to replace the default Runtime .lib 
library with the RSRCRuntime. lib library. This library is like Runtime .lib except that it uses 
register A4 to access globals and doesn’t contain the Pascal I/O routines. (This means that you can’t 
use writeln in a code resource, for instance.) 

Note: To change the library, hold down the Option key as you double-click on 
the library name. THINK Pascal displays a standard file dialog that lets you choose 
the replacement file. 

In multi-segment code resources, variables and jump table entries are addressed as offsets from A4. 
Unlike drivers, however, A4 isn’t set up automatically for you when your main routine is called. 
You have to do this yourself. Immediately after you enter main, you must call RememberA4 and 
SetUpA4. RememberA4 saves the value of A4 where the SetUpA4 can find it. You must call 
RestoreA4 before you return from main..This is what the main routine for your code resource 
should look like: 

procedure main; 
begin 

RememberA4; 

SetUpA4; 

RestoreA4; 

end; 

All calls to SetUpA4 and RememberA4 must be from the same segment that contains main. This 
means that the file that contains main, RSRCRuntime. lib, and any files that contain calls to 
SetUpA4 and RestoreA4 must be in the same segment. 

As with the other project types, segments are loaded automatically as they are called. However, 
unlike the other project types, you must unload the segments yourself when the code resource 
exits. You can unload individual segments with this function: 

procedure UnloadA4Seg(routine: ProcPtr); 

This function works just like UnloadSeg does in applications. To unload one segment, call 
UnloadA4 Seg with the address of a routine in that segment; for example, 

UnloadA4Seg (@foo). To unload all segments at once, call UnloadA4Seg with nil; that is, 
UnloadA4Seg (nil) . Before you call RestoreA4, it’s a good idea to call UnloadA4Seg (nil) 
to make sure that all your code resource’s segments are unloaded. 

Note: Do not use UnloadSeg instead of UnloadA4Seg by mistake! 

In code resources, the segment that contains the main routine is special. The jump table and global 
data for all the segments are appended to the segment that contains main, so the resource’s global 
data, the jump table, and the main segment’s code must be less than 32K. 


169 




THINK Pascal User Manual 


Note: If your code resource uses Object Pascal or global data, you must check the 
Multi-Segment option even if your driver contains only one segment 

Using code resource globals In callback and trap Intercept routines 

If your multi-segment code resource uses callback, trap intercept routines, or other functions that 
might be called when the value of A4 is in doubt, you have to save A4 where your routines can 
find it The special library for multi-segment code resources, RSRCRuntime . lib, contains the 
procedures SetUpA4 and RestoreA4 that take care of setting and restoring A4 for you. 

All calls to SetUpA4 must be from the same segment that contains main. This means that the file 
that contains main, RSRCRuntime .lib, and any files that contain calls to SetUpA4 and 
Rest ore A4 must be in the same segment. 

Suppose your code resource calls ModalDialog with a f ilterProc. Since you’re not sure if the 
value of A4 will be correct when ModalDialog calls your f ilterProc, you need to set A4 to 
the proper value. Your f ilterProc would look like this: 

function MyFilterProc(dp : DialogPtr; var event: EventRecord; 

var item : integer) : Boolean; 

var 

result : Boolean; 

begin 

SetUpA4; 

MyFilterProc := result; 

RestoreA4; 

end; 

Use the same technique for trap intercept routines. Of course, if your callback or trap intercept 
routine doesn’t use code resource globals, you don’t need to set up and restore A4. 


170 




Building Projects 12 


Putting It Together 

When you’re finished developing your application, desk accessory, device driver, or code resource, 
choose one of the Build... commands in the Project menu. The actual name of the Build... com¬ 
mand could be Build Application..., Build Desk Accessory..., Build Driver..., or Build Code 
Resource..., depending on the project type. When you choose one of the commands, you’ll see a 
dialog box like this: 


Q Applications | 




c=>Tess 



l J 



( 1 




Saue Rpplication as 


[ Saue ] 

RboutBoK 1.0d23 

| [ Cancel ] 


£x] Smart Link 


When THINK Pascal puts your final file together, it compiles all the files that need to be recom¬ 
piled. If you’re building an application, and you have the Debug option on, THINK Pascal 
recompiles all the files with the Debug option turned off. 

Note: THINK Pascal does not change any of the other compiler options during a 
build. You will probably want to disable Range and Overflow checking yourself. 

To make your final file as small as possible, THINK Pascal uses a technique called smart linking. 
THINK Pascal examines all the routines that your project uses. If there are functions, procedures, or 
methods that your program doesn’t reference, it doesn’t incorporate their code in the final file. 

Smart linking yields a smaller final application, but it takes longer to produce it. If you’re doing a lot 
of builds you might want to turn smart linking off. Just click on the Smart Link check box when you 
build your final file. 

After THINK Pascal links your program, it produces the application, desk accessory, device driver, 
or code resource file. At the end, it copies the resources from the resource file you specified in the 
Run Options... dialog into the final file. 


171 






Assembly Language 

13 


Introduction 

Most of the Macintosh Toolbox routines expect to be called from Pascal. The data types used by 
the routines are usually described as Pascal records, pointers, and arrays. That’s why working in 
Pascal on the Macintosh is a natural fit. 

Of course, deep inside the Macintosh works in MC68000 machine language. For some specialized 
tasks, assembly language is the only way to get the job done. 

This chapter shows you how to use assembly language routines in your THINK Pascal programs. It 
begins with an overview of the Macintosh software environment and a description of how Pascal 
data structures exist within that environment. Next is a description of Pascal calling conventions so 
you can be sure that your assembly language routines are well-behaved. Finally, this chapter shows 
you how to use assembly language routines written in other development environments with 
THINK Pascal. 

Even if you don’t plan on writing or using assembly language routines in your programs, this chap¬ 
ter will give you enough background to help you use the built in LightsBug debugger as well as 
low level debuggers like TMON or Macsbug. 

What you should know 

This chapter assumes you know about MC68000 assembly language. But you don’t have to be a 
proficient assembly language programmer to understand this chapter. And although this chapter 
gives you an overview of the Macintosh software architecture, it doesn’t go into too much detail. To 
learn more about how the Macintosh manages memory and how it loads your program, read Inside 
Macintosh II, Chapter 1, “The Memory Manager,” Inside Macintosh II, Chapter 2, “The Segment 
Loader,” and Inside Macintosh VI, Chapter 28, “Memory Management.” 

If you plan to write assembly language routines to use in THINK Pascal, you can use THINK C or 
Apple’s Macintosh Programmer’s Workshop. 

Topics covered In this chapter 

• The runtime environment 

• Pascal data types 

• Pascal calling conventions 

• Using assembly language 


173 



THINK Pascal User Manual 


The Runtime Environment 

While your program is running, all memory is divided into three parts: the stack, the heap, and the 
A5 world. 

The Stack 

The stack is an area of memory that is dynamically allocated and deallocated in a strict last-in-first- 
out fashion, like a stack of trays in a cafeteria. The MC68000’s A7 register is reserved as a stack 
pointer. It always contains the address of the top of the stack. 

Note: The stack in the MC68000 actually grows downward, towards lower mem¬ 
ory addresses, so the top of the stack is actually the byte in the stack with the 
lowest address. 

The stack contains information about the activation and deactivation of procedure and functions. 
Each time a routine is called, a stack frame is allocated. The stack frame contains all of the rou¬ 
tine’s parameters, local variables and temporaries, and the return address. When the routine exits, 
the stack frame is released and the context of the calling routine is restored. The register A6 is the 
frame pointer of the currently active procedure or function. 

The Heap 

The heap (also called a zone in Macintosh terminology) is the area of memory that the Macintosh 
uses to allocate dynamic data structures like windows, menus, resources, the code for the program 
itself, and other heap zones. 

The Macintosh Memory Manager takes care of all the housekeeping chores. It knows where a new 
block can be allocated, what to do with deallocated blocks, and how to compact the heap when it 
needs space. 

The memory within a heap is divided into three kinds of blocks: 

• Free Blocks. These blocks represent unused heap memory that may be allocated to satisfy a 
memory request. 

• Non-relocatable Blocks. These are allocated blocks of memory that reside at a fixed location. 
They are referenced by a pointer to the block. 

• Relocatable Blocks. These are blocks that the Memory Manager can move around to make more 
room in the heap for larger blocks. Because a relocatable block can move, your application 
can’t keep a pointer to it. Instead, the Memory Manager maintains and updates a master pointer 
that points to the block of memory. The Memory Manager gives you a handle, a pointer to the 
master pointer, so you can access the block. To access a relocatable block, you dereference the 
handle twice. 

The Memory Manager is one of the fundamental parts of the Macintosh operating system. There is a 
great deal of myth and lore concerning its effective use. For more information, see Inside 


174 




Assembly Language 13 


Macintosh II, Chapter 1, “The Memory Manager” and Scott Knaster’s How to Write Macintosh 
Software. 

The A5 World 

The A5 world is a colloquial term for the area of memory that is referenced through register A5. 
The A 5 world looks like this: 


A5 


(A5) 


jump table 


application params 


ptr to QD globs 


application globals 


QuickDraw globals 


• The 32 bytes from the memory location specified in register A5 contain the application pa¬ 
rameters. This is information used and maintained by the system. The only part of this section 
you might use is 0(A5) which contains a pointer to the beginning of the QuickDraw globals. 

• Immediately following the application parameters is the jump table. The Segment Loader uses 
the jump table to load and unload segments of code. Every procedure and function that is refer¬ 
enced across segments has an entry in this table. For more information about the Segment 
Loader see Inside Macintosh II, Chapter 2, “The Segment Loader.” To learn how to break up 
your THINK Pascal program into segments, see Chapter 7. 

• The area of memory below A5 is reserved for the application globals. All of the globals that 
your application defines are stored here, as are the QuickDraw globals. 


175 




THINK Pascal User Manual 


The A4 World 

If you build a multi-segment desk accessory, device driver, or code resource, you use the A4 world. 
The A4 world is a colloquial term for the area of memory that is referenced through register A4. 

The A4 world looks like this: 



• A4 points to the beginning of your globals. All of the globals that your program defines are 
stored here. 

• Immediately following your globals is the jump table. The Segment Loader uses the jump table 
to load and unload segments of code. Every procedure and function that is referenced across 
segments has an entry in this table. For more information about the Segment Loader see Inside 
Macintosh //, Chapter 2, “The Segment Loader.” To learn how to break up your THINK Pascal 
program into segments, see Chapter 7. 

Pascal Data Types 

When you’re writing an assembly language routine, you need to know how THINK Pascal stores 
the various Pascal data types in memory. 

Integer Types 

Integers of type integer are represented as a 16-bit two’s complement number with a range of 
-32,768 to 32,767. 

Integers of type longint are represented as a 32-bit two’s complement number with a range of 
-2,147,483,648 to 2,147,483,647. 

Subranges of integer in the range -128 to 127 are represented in 8 bits. Subranges with bounds 
outside this range occupy 16 bits. 

If an integer subrange is a component of a packed array and it is in the range 0 to 255, it is repre¬ 
sented as an unsigned byte (8 bits). If an integer subrange is a component of a packed record and it 
is in the range 0 . . 65535, it is represented with the least number of bits possible. (For example, 
the subrange 0 . . 15 would be represented in 4 bits.) 


176 




Assembly Language 


13 


Chars 

The type char is represented as a 16-bit value with the extended ASCII code of the character in the 
low-order byte, and 0 in the high-order byte. 

If a char is a component of a packed structured-type, it is represented as an unsigned byte (8 bits). 
If a character subrange is a component of a packed record, it is represented with the least number 
of bits possible. (For example, the subrange * a * . . 1 z 1 would be represented in 7 bits.) Other 
packed structured-types represent character subranges with 8 bits. 

Booleans 

The type boolean is represented as a byte. It may assume only the values 0 (false) or 1 (true). 

If a boolean is a component of a packed structured-type, it is represented as a bit (1 bit). 

Enumerated Types 

Enumerated types are represented as unsigned bytes. They may assume ordinal values in the range 
0 to 255 depending upon the number of enumerated constants in the type. 

If an enumerated type is a component of a packed record, it is represented with the least number 
of bits possible. (For example, the enumerated type (mo n, tue, wed, thu, fri, sat, 
sun) would be represented with 3 bits.) 

Real Types 

The real-types real, double, and extended are represented as IEEE-format floating-point num¬ 
bers of 32, 64 and 80 bits respectively. The real type COMPUTATIONAL is represented as a 64-bit 
two’s complement integer. 

Note: If you compile your program with the 68881/68882 option, extended 
values are 96 bits long. To learn more about the 68881/68882 option, see Chapter 
15. 

The floating-point formats are described in complete detail in Apple Numerics Manual, Second 
Edition (Addison-Wesley) 

Pointers 

Pointer-types are represented as 32-bit address values. Only the low order 24 bits contain the ad¬ 
dress. The Macintosh Memory Manager uses the high-order 8-bits, and they are not guaranteed to 
be 0. Use the Toolbox routine StripAddress to turn a Memory Manager address into a canonical 
address before doing any pointer arithmetic. 

Strings 

A string of size n has a 1 byte length field followed by n bytes containing the character compo¬ 
nents of the string (each occupying a single byte as if packed). An unused byte is added to the end 
if needed to ensure that the total number of bytes is even. 


177 



THINK Pascal User Manual 


Arrays 

An array with index [L. . H] is represented as if H-L+l variables of the component type were laid 
end to end. If the size of the component type is not 1, it is first rounded to an even number of byles 
so that each element of the array is on an even byte boundary. An unused byte is appended to the 
array if necessary to ensure that it occupies an even number of bytes. 

A multidimensional array of indices [ LI. . HI, L2 . . H2, ..., Ln. . Hn] is represented as if it 
were declared as an array of index [ LI. . HI ] with a component array of index [ L2 . . H2 ] with a 
component array of index [ L3 . . H3 ], etc. 

A packed array is identical to the corresponding array type unless the component type is packable 
(e.g., CHAR or integer subrange in the range 0 . . 255) in which case the components are allocated 
in their packed format. 

Records 

A record with fields f 1: T1, f2 : T2, ..., f n: Tn is represented as if each field were a single 
variable and all fields were laid end to end. If a field’s size is not 1, the field is first aligned to an 
even boundary. An unused byte is appended to the rest of the record if necessary to ensure that it 
occupies an even number of bytes. 

A packed record is identical to the corresponding record type unless the types of one or more 
fields are packable (e.g., CHAR or integer subrange in the range 0 . . 255) in which case the fields 
are allocated in their packed format. These are the types THINK Pascal packs: 


Type 

Example 

Range 

# Bits 

Any boolean type 

Boolean 

0. .1 

1 

Any character type or 

char 

0. .255 

8 

subrange 

'a'..'z' 

0. .122 

7 

Any enumerated type 

(mon, tue, wed, 
thu, fri, sat, sun) 

0. .6 

3 

Any integer subrange in 

0. .15 

0. .15 

4 

the range 0 . . 65535 

0..65535 

0. .65535 

16 


To make a packed record, THINK Pascal packs the fields into the byte starting from the most signif¬ 
icant bit to the least significant bit. It packs the fields as tightly as the word-alignment rules let it 
For example, this record: 

packed record 


fO: 

Cha r ; 

{ 

8 

bits } 

fl: 

Boolean; 

{ 

1 

bit } 

f 2 : 

0. .127; 

{ 

7 

bits } 


end; 


178 



Assembly Language 13 


is packed neatly into two bytes: 
0 


15 


fO 


fl 


f 2 


But this record: 

packed record 


fO: 

Char; 

{ 

8 

bits } 

fl: 

Boolean; 

{ 

1 

bit } 

f 2 : 

0. .32767; 

{ 

15 bits } 


end; 

must be packed into four bytes (empty fields are unused): 


0_7_8_14 15 


fO 


1 fl 1 

0 

1 


15 

1_ 

f 2 


To avoid straddling an odd byte boundary, THINK Pascal must place the 15-bit field f 2 in a differ¬ 
ent byte from f 1. Note that if the fields of a packed record do not completely fill a word, THINK 
Pascal aligns the fields to the least significant bit-position where possible to access the field more 
efficiently. 

Sets 

Sets are represented as bit arrays where each bit indicates whether the corresponding element is in 
the set or not. Sets occupy an even number of words, and are always allocated as if the set origin 
were 0: a set of 0 .. 255 occupies the same number of bytes as a set of 100.. 255. 

Note: A set with elements in the ordinal range 0 . . 7 is stored as a byte. However, 
when passed as an actual value parameter, the set is first extended to a word, so 
the value ends up in the low-order byte rather than the high-order byte. 


Files 

A f ile is represented as a record of 58 bytes of status information followed by a component 
buffer whose size is equal to the size of the component type of the file. 

Files of type text are represented identically to packed file of char. However, the prede¬ 
fined routines eoln, writeln, and readln can only be used with files of type text. See Section 
9 of Chapter 17. 


179 






THINK Pascal User Manual 

_o_ 


Pascal Calling Conventions 

Most of the Macintosh Toolbox routines expect to be called as if from Pascal. When you write your 
assembly language routines, be sure that they follow the Pascal calling conventions. 

Pascal calling sequence 

If the routine is a function, it is the caller’s responsibility to reserve space on the stack for the return 
value. The caller then pushes the arguments in left-to-right order and calls the function. Upon 
return, the result (if any) may be found on the stack. The caller’s code looks something like this: 


SUBQ 

#n, SP 

; reserve space for result 

MOVE 

argl f -( sp) 

; first argument 

MOVE 

argn, -(SP) 

; last argument 

JSR 

routine-addr 


MOVE 

(SP) +, result 

; result 


If the called routine is a stack-based Toolbox trap, THINK Pascal generates the appropriate trap 
word instead of the JSR instruction. For all other routines, the compiler generates a JSR 
instruction. 

Note: For register-based traps, for routines dispatched through a single trap, or 
for routines marked [Not in ROM] the JSR goes to glue code in 
Interface. lib. 

If the “Far Code” option is on, there might be a NOP (no-op) instruction after the JSR instruction. 
The instruction is needed because the linker replaced a 32-bit address with a 1 6 -bit address. When 
the Far Code option is on, the code generator uses a 32-bit absolute address to a jump table entry 
for routine-addr. If the called routine is in the same segment as the caller, the linker replaces the 
32-bit routine-addr with a 1 6 -bit relative address off A5 and a 1 6 -bit NOP instruction. This 
replacement makes it more likely that the linker can delete the jump table entry for that routine. 
For more information on the Far Code option, see “Building applications with large jump tables” in 
Chapter 12. 

If the called routine is in a nested scope, the caller also provides the static link, the frame pointer of 
the most recent activation of the nesting procedure or function. It’s very unlikely that any assembly 
language routines you write will need a static link. 

Pascal routine entry 

Just after the call to the Pascal routine, the return address is on the top of the stack. Most of the 
time, the routine will create a stack frame with the LINK instruction, and it will save any non- 
scratch registers. 


180 




Assembly Language 13 


As the routine begins, the stack looks like this: 


return value 
first argument 


last argument 
static link (opt) 
return address 
A6 previous A6 

local variables 
SP saved registers 


The function’s code looks something like this: 

LINK A6, #... ; (optional) 

MOVEM.L -(SP) ; (optional) save registers 

; code for the routine 

The last argument can be found at 8 (A6). If there was a static link, the last argument is at 12 (A6). 
You can find the first local variable at a negative offset from A6. The value of the offset depends on 
the size of the variable. 

Note: You generally don’t need to worry about static links. 

All arguments occupy 2 or 4 bytes on the stack. A byte argument appears in the high byte of its 
word and is found at an even offset from A6. 


Pascal routine exit 

When a Pascal routine exits, it is responsible for deallocating its stack frame and for removing any 
arguments from the stack. So the end of Pascal routine looks like this: 


MOVEM.L (SP)+,... 
UNLK A6 

MOVE (SP)+,AO 

ADD #..., SP 

MOVE (SP) 

JMP (AO) 


(optional) restore registers 
(optional) 

return address in AO 
total size of arguments 

including static link if necessary 
store return result 
return to the caller 


The code that THINK Pascal actually generates to return from a function may be slightly different 
because the compiler optimizes the stack cleanup. If you have the MC68020/MC68030 option on, 
for instance, THINK Pascal uses an RTD instruction to clean up the stack and return to the caller. 


181 







THINK Pascal User Manual 


Parameter passing 

The way you push parameters on the stack depends on the size and kind of parameter. 

For this parameter... Do this... 

var parameter Push the address of the actual parameter on the stack. 

Value parameter If the size of the actual parameter is 4 bytes or less, push the value of 

the parameter. All values take up either 2 or 4 bytes on the stack. A byte 
value appears in the high byte of the word, and you can find it at an 
even offset from register SP or A6. 

If the size of the parameter is greater than 4 bytes, pass the address of 
the actual parameter. It is the responsibility of the called routine to 
make a copy of the parameter in case it is modified. 

Procedural parameter Push the address of the procedure or function, then push the static link 

to be used when the routine is actually called. If the procedure or 
function is declared in the outermost scope, pass a 0 for the static link. 

Note: A procedural parameter is not the same thing as passing a pointer to a 
procedure or function. 

Return Values 

If the size of the return value of a function is 4 bytes or less, the caller allocates 2 or 4 bytes on the 
stack for it. When the function returns, this value is left on the stack. 

If the size of the return value is more than 4 bytes, the caller allocates a temporary variable of the 
appropriate size and pushes its address as a “hidden parameter.” When the function returns, the 
caller discards the address of the hidden parameter. 

Register saving conventions 

You can use registers DO, Dl, D2, AO, and Al freely in your assembly language routines. If you 
need to use other registers, be sure to save and restore them. If the machine you’re programming 
for has a MC68881 or MC68882 floating point unit, you can use registers FPO, FPl, and FP2. 

Note: Because registers A5, A6, and A7 are used to maintain vital state informa¬ 
tion between calls to subroutines, you should try to avoid using them except to 
access globals variables, local variables, frame pointers, etc. If you push 
something on the stack, be sure to pop it off. 

Using Assembly Language 

You can use THINK C and Apple’s Macintosh Programmer’s Workshop (MPW) to write assembly 
language routines that you can use in THINK Pascal. You can add THINK C libraries and MPW 
object files directly to your THINK Pascal project. Read the sections below to learn how to use code 
from these development systems with THINK Pascal. 


182 



Assembly Language 13 


Note: Even though they may use the same format, THINK Pascal can’t use some 
. o files created by some high-level language compilers, like MPW C or Pascal. 

You can use . o files created with the MPW assembler, as well as libraries created 
with THINK C. For more information, see “Using . o Files,” Appendix C. 

When you write a routine in assembly language, it’s up to you to make sure that you follow the 
proper Pascal calling conventions and that you call it correctly from Pascal. For example, suppose 
that you wrote a function, NewSysHandle, that creates a new handle in the system heap. The 
function takes a longint that is the size of the handle, and it returns the new handle. To use the 
function, you would put this declaration in your Pascal program: 

function NewSysHandle(size : longint) : Handle; 
external; 

The external directive tells THINK Pascal to look for NewSysHandle when it links your program. 
Presumably, the routine is in a library that you’ve added to your project. 

THINK Pascal honors data initializations from imported THINK C libraries and MPW . o files. For 
example, take these declaration from a THINK C library: 

char myString[] = "\psome string"; 
static ProcPtr myHook = &myFunction; 

When the library is loaded, the value of my St ring will be " \psome string", and ProcPtr 
will point to my Function. 

However, in desk accessories and drivers, libraries and . o files may not initialize variables to be 
pointers to other variables or to functions (that is,they may not use initializations that require run¬ 
time relocations). For example, THINK Pascal would honor the first initialization above in a desk 
accessory or device driver, but it would not honor the second. 

Using THINK C with THINK Pascal 

To write the NewSysHandle function in THINK C, write it like this: 


pascal void Handle NewSysHandle 
{ 


asm { 

move.1 
_NewHandle 
move.w 
move. 1 


size, dO 
SYS 

dO, 0x220 
aO, dO 


(long size) 


; size of handle in dO 
; call the trap 
; put result in MemErr 
; put return in DO for THINK C 


} 


The pascal keyword instructs THINK C to use Pascal calling conventions. This way, you can let 
the compiler worry about following the rules while you write the meat of your routine in assembly 
language (or, if you prefer, in C). 


183 




THINK Pascal User Manual 


If you’d rather take care of managing the stack yourself, you can write the routine this way: 

void NewSysHandle(void) 

{ 

asm { 


movea.1 

(sp )+, al 

; get return address 

move.1 

(sp)+, dO 

; size of handle in dO 

_NewHandle 

SYS 

; call the trap 

move.w 

dO, 0x220 

; put result in MemErr 

move.1 

a0, (sp) 

; put result on stack 

jmp 

(al) 

; return to caller 


} 

} 

To use Pascal global symbols from THINK C source files, just declare them extern and use them 
as you would any other C symbol. 

After you compile the file, use the THINK C Build Library... command to create a library. Since 
you can load THINK C libraries directly into THINK Pascal projects, that’s all you have to do. 

To learn more about writing Pascal compatible routines in THINK C, see Chapters 10, “The 
Compiler,” and 13, “Assembly Language,” of the THINK C User’s Manual. 

Using Apple’s Macintosh Programmer’s Workshop 

To write the NewSysHandle function with Apple’s Macintosh Programmer’s Workshop, write the 
assembly language file like this: 

INCLUDE 'SysEqu.a' 

INCLUDE 'Traps.a' 

NewSysHandle PROC EXPORT 

movea.l (sp)+, al ; get return address 

move.l (sp)+, dO ; size of handle in dO 

_NewHandle SYS ; call the trap 

move.w dO, $220 ; put result in MemErr 

move.l aO, (sp) ; put result on stack 

jmp (al) ; return to caller 

ENDP 

END 

To access Pascal global symbols from MPW assembly language files, declare them external with the 
IMPORT directive and reference them from register A5 for applications or register A4 for desk ac¬ 
cessories and device drivers. 

Once you assemble the file, you can use the Add File... command to add an MPW object file to 
your THINK Pascal project. 


184 




LightsBug 

14 


Introduction 

This chapter shows you how to use LightsBug, THINK Pascal’s powerful debugging tool. LightsBug 
lets you get a close-up view of your program. When you stop your program, you can see all the 
procedures and functions that called the routine you’re stopped in, the values of all the local and 
global variables, all the blocks in the application and system heaps, the CPU registers, and any part 
of memory. 

What you should know 

LightsBug knows about things like procedures, functions, arrays, and records, and it knows about 
low-level Macintosh objects like heap zones. For an overview of the Macintosh Memory Manager, 
see Inside Macintosh /, Chapter 3, “Macintosh Memory Management: An Introduction.” To learn 
about the technical details of the Memory Manager, see Inside Macintosh II, Chapter 1, “The 
Memory Manager,” and Inside Macintosh VI, Chapter 28, “Memory Management.” 

You’ll find LightsBug more useful if you know something about memory organization and Pascal 
calling conventions. You can learn about these things in Chapter 13, “Assembly Language.” 

Topics covered In this chapter 

• Using LightsBug 

• Subroutine call chain 

• Examining variables 

• Examining structured variables 

• Examining many variables 

• Using watchpoints 

• Type casting variables 

• Examining registers 

• Examining heap zones 

• Displaying memory 

• Editing memory 

• Debugging Toolbox routines 



THINK Pascal User Manual 


Using LightsBug 

LightsBug works best when you have both the Debug and the Names options turned on. To learn 
about these options, see Chapter 7, “Working with Projects,” and Chapter 15, “Compiler 
Directives.” 


When you choose the LightsBug command from the Debug menu, you’ll see a LightsBug window 
like this: 


LightsBug-1 


DrauiOnaShap* 

| >???????? 

TDrautU i ndotu. DoUpl 
HandleUpdate 
MainLoop 


HProcedure TShap*.Drew 

True fill It 
0024R48C SELF 


Boolean 
TShape 


GIobaI vartables 
00249C10 
0024R500 


fippIeMenu 
Co I orMenu 


MenuHandIe 
MenuHandIe 


DragauariabletothisHagnifgingGlass icon to see an expandedview" 


: 1 rtWlWIWWWWlrt l S Offset: ! 00001 [Ed i 
0081 0000 4080 2R14 0024 24F0 0024 24F2 

0024 24F4 0024 24F6 0024 24F8 0024 24FR 

4080 2106 4080 2108 4080 64BR 0024 2502 

4080 210E 4080 210E 4080 210E 4080 210E 

4080 210E 4080 210E 4080 210E 4080 210E 

4080 210E 4080 210E 4080 210E 4080 210E 


.A. .8R*..$$□.$$□ 

8R!.8fl!.®fldj.|*. 
*R!.8fi!.8fl!.8fl!. 
8RI.8R!.8fl!.®fi! 


8fl! 


. 8R! . 8fl! 




The LightsBug window looks more complicated than other THINK Pascal windows because it lets 
you work with a running program in several different ways. 

The LightsBug window is divided into four panes. The upper right pane and the middle pane can 
have different displays depending on how you use LightsBug. It may sound complicated, but once 
you experiment a little, using LightsBug will become as easy as using other parts of THINK Pascal. 


The upper left pane always shows you the subroutine call chain. The upper right pane displays 
subroutine variables, the CPU registers, and heap zones. The middle pane displays expanded views 
of variables, variables that you’ve put into a collected view, and watch points. The bottom pane 
always shows you the contents of your Macintosh’s memory. 

Working with panes 

To make a pane larger or smaller, drag the double line that separatesthe panes. To get rid of a 
pane altogether, drag the double line to the edge of the window. To get a pane back, just drag the 
double line back from the edge of the window. 


THINK Pascal lets you open up to four LightsBug windows. To create another LightsBug window, 
choose the New LightsBug command. To see the New LightsBug command, hold down the Shift 
key as you select the Debug menu.If there is more than one LightsBug window on the screen, 
choosing the LightsBug command cycles through all the open windows. 


186 















LightsBug 14 


The LightsBug Icons 

The icons along the left edge of the LightsBug window control the displays in the LightsBug panes. 
The icons are divided into four groups. 



MUM 

variable display 
register display 
heap display 

B 1 

B' 

A 

expanded view 


collections 

m 

watchpoints 

m 

edit value 


typecast value 

0 

trash 

fflg 

o: 



LlghtsBug-1 


TDrawUindow.Dot 
Hand IeUpdate 
hainLoop 

a variable 


Procedure TShape.Dra* 

True fllllt 

-_JDQ2S£ttfiSS_SOLE.. 

Global variables 


BooIeon 
.IShape. 


00249C10 Rpplehenu : MenuHandIe 

00248500 Colorhenu : henuHandle 

I ass i con to see an expanded v i 


B Offset: 100001 Ifedi tl 
0000 4080 2R14 0024 24F0 0024 24F2 
24F4 0024 24F6 0024 24F8 0024 24FR 
2106 4080 2108 4080 64BR 0024 2502 
210E 4080 210E 4080 210E 4080 210E 
210E 4080 210E 4080 210E 4080 210E 
210E 4080 210E 4080 210E 4080 210E 


.A. .CR+..$$□.$$□ 

®fl!.8RI.efldj.$*. 

8fl!. 8fi!.Cfl!. Bfi!. 


The first group of icons controls the display in the upper right pane of the LightsBug window. 


□ 


Variable display. When you choose this icon, the pane displays all the 
variables visible to the routine selected in the subroutine call chain. 





Register display. When you choose this icon, the pane displays all the 
CPU registers in hexadecimal. If you have the 68881/68882 option on, the 
pane also displays the floating point registers. 

Heap display. When you choose this icon, the pane displays your 
application heap zone or the system heap zone. 


The second group of icons controls what you see in the center pane. These icons work like 
containers — like folder icons in the Finder. You drag values into them. 





Expanded view. When you drag a variable name from the variable display 
into this icon, the center pane displays its value. If the variable is a struc¬ 
tured type (a record, an array, or a set), the display shows you all the fields 
or elements. 

Collected views. This container is like the expanded view container, but it 
can hold more than one value at a time. You can place several different 
values here so you can keep track of them all at once. 

Watchpoints. This container also holds several values at once. Whenever 
one of the watchpoints changes, THINK Pascal stops your program. 


187 














THINK Pascal User Manual 


The third group of icons lets you edit values. These icons work like filters. You drag something into 
them and get something else. 

ff Edit value. When you drag a value into this icon, LightsBug displays a 

Y dialog box that lets you edit the value. 

*9o* Type cast value. When you drag a value into this icon, LightsBug displays 

a dialog box that lets you change the type of a value. For example, you can 
change a generic handle into a ControlHandle. 

The last icon is like the Trash icon in the Finder. It lets you remove values from any of the 
containers. 

j|n[ Trash. When you drag a value from any of the containers — expanded 

view, collection views, or watchpoints — to this icon, the value is removed 
from the container. Unlike the Finder, you can’t drag things out of the trash 
in LightsBug. 


Examining Subroutines 


The upper left pane of the LightsBug window is the subroutine call chain. It shows you the list of 
all the subroutines that are currently active — all the subroutines that have been called but haven’t 
returned yet. The most recently called subroutine is at the top of the list. 


DrawOneShape 

>???????? 

TDr awU i ndoui. DoUpda te 
Hand I ellpdate 
HainLoop 
-OBJECTDR 


LightsBug does its best to find the names of the subroutines in the call chain. When the subroutine 
is compiled with the Debug option on, and it is in an open window, LightsBug uses the full name 
of the routine. Otherwise, LightsBug uses the name stored in the code when the Names option is 
on. (See Chapters 7 and 15 to learn more about the Names option.) 


188 






LightsBug 14 


LightsBug uses a system of case conventions and prefixes to let you know how the subroutine was 
compiled. 


Name Display 

MyProc_Name 


MYPROCNA 




no prefix 


> 


Meaning 

The subroutine is in an open editing window and was compiled 
with the Debug option on, or the subroutine was compiled with 
both the Names and the Full Length names options on. 

The subroutine is not in an open editing window, or the subroutine 
was compiled with both the Names on and the 8-Character names 
options on. 

The routine was compiled with the Names option off, and either it 
is not in an open editing window or it was compiled with the 
Debug option off. 

The subroutine is in an open editing window and was compiled 
with the Debug option on. 

The subroutine is not in an open editing window and was compiled 
with the Debug option on. 

The subroutine was compiled with the Debug option off. 


There was a gap in the call chain. This usually happens when an 
assembly language routine uses register A 6 in an unusual way. 


In the picture above, OBJECTDR is the program name. OBJECTDR called a procedure MainLoop 
which called HandleUpdate which called TDrawWindow. DoUpdate. 

TDrawWindow. DoUpdate called a routine which was compiled with the Names option off. It is 
listed as ????????. That routine in turn called DrawOneShape which called TShape.Draw. 
Note that OBJECTDR is marked as not being in an open editing window. ???????? is marked as 
having been compiled with the Debug option off. 

When a subroutine is called recursively, its name will appear more than once in the subroutine call 
chain. 


189 






THINK Pascal User Manual 


Finding a routine definition using the call chain 

You can use the subroutine call chain to find the definition of a procedure, function, or method. 
When you double-click on a routine, THINK Pascal opens the file that contains the routine and 
points to the line it last executed (that is, where it called the next routine in the chain). For 
example, if you double click on DrawOne Shape: 



I>??r 

TDrawUindow.DoUpl 
Hand I ellpdate 
MainLoop 


Procedure DrawOneShape 

0 hComp : Integer 

00242624 o : TObject 

_Conp_.L_i.0A«g«C.— 

Global variable* 

00241088 RppleMenu : henuHandh 


I Drag a varii 


to thisMagnifgingGlass icon to see an expanded view 


Base: 

000 

010 

020 

030 

040 

050 


0081 

0023 

4080 

4080 

4080 

4080 


0000 

R66C 

2106 

210E 

210E 

210E 


0 Offset: 
4080 2R14 
0023 R66E 
4080 2108 
4080 210E 
4080 210E 
4080 210E 


OOOOl [Edit] 


0023 R668 0023 R66R 
0023 R670 0023 R672 
4080 64BR 0023 R67R 
4080 210E 4080 210E 
4080 210E 4080 210E 
4080 210E 4080 210E 


.A. .Cfl*. 

.«fll ."Hn. 

Cfl!.8fl!.efldj.•Hz 
Cfll.8RI.8fl!.®fl!. 
8RI.Cfl!. Cfl!.8R!. 
8fl!.§fi!. ®fi!.8flI. 




you’ll see this editing window: 


m 

Or 

ODTDrawLUindow.p . . . 

procedure DrawOneShape Co: TObject); 

begin 

if gDrawWindow.drawOnScreen then 

TShape(o).0ffset((gDrawVindow.hOffset - gDra w Window .deltaH), -CgDrawV 

TShape(o).Draw(TRUE); 

if gDrawWindow.drawOnScreen then 

TShape(o).0ffset(-(gDrawVindow.h0ffset - gDrawWindow.deltaHX CgDrawV 

end; 

Qi 

5 

ifc 

l| 

o 




a 


190 






















































































































































LightsBug 14 


Examining Variables 

When you select a subroutine name from the subroutine call chain, the upper right pane becomes 
the variable display. This display shows you the names, types, and values of all variables 
(including parameters and global variables) visible to the subroutine. 



LightsBug-1 


'amuneShape 
>???????? 

TDrawUindow.DoUpl 
HandleUpdate 
MainLoop 


Procedure TShape.Draw 

True fiI I It : Boolean 

.QQ24R48£ £&£._:...TShap.e... 


MffToBsnnwrKr 

|: * :M 00249C10 flppleMenu 

0024R500 Colorhenu 


henuHandIe 
henuHandle 


I Drag a variable to this Magnifying Glass icon to see an expanded view. 1^.1 


Base: 

000: 0081 


010 : 

020 : 

030: 

040: 

050: 


0000 
0024 24F4 
4080 2105 
4080 210E 
4080 210E 
4080 210E 


S Offset : f0000l [EditI 
4080 2R14 0024 24F0 0024 24F2 
0024 24F6 0024 24F8 0024 24FR 
4080 2108 4080 64BR 0024 2502 
4080 210E 4080 210E 4080 210E 
4080 210E 4080 210E 4080 210E 
4080 210E 4080 210E 4080 210E 


.A..eft*..$$□.$$□ 

ffl! ffl!.efldj.i*. 
Bfl! .8R! .6fl! .8fl« . 
8RI.8RI.Bfl!.Bfl!. 

Bfl!.Bfl!.Bfl!.eft!. 


The variables are listed in alphabetical order. 

Variables and scope 

LightsBug displays all the variables visible to the selected subroutine according to Pascal’s scoping 
rules. That means that every variable you could reference in the selected routine appears in the 
variable display. If the selected routine is nested within another routine, you’ll see the variables for 
the enclosing routine. 

A dotted line separates the variables for each routine. The first line of text under the dotted line tells 
you whether the routine is a procedure or a function. If the routine is a function, LightsBug displays 
its return value right under the name. 

Global variables appear at the end of the variable display. Since the display shows only the vari¬ 
ables that are visible to the selected subroutine, you’ll see only the global variables that are in units 
known to the subroutine. 


Variable display formats 

LightsBug displays the value of a variable in the most natural format for its type: 


Variable type 

INTEGER 

CHAR 

String 


Display format 

12,-7 3 (decimal) 
'F', CHR(13) 

'A String' 


191 




















THINK Pascal User Manual 


Variable type 

Enumerated, BOOLEAN 
Pointer, Handle, Object 
Array, Record, Set 


Display format 

TRUE, FALSE, RED, WHITE 
00031F36 (hexadecimal value) 
<array>, <record>, <set> 


If a character isn’t in the printable range, LightsBug uses the form CHR (n) so you can see its value. 
A carriage return, for instance, would be displayed as CHR (13). 

Note: When you click on a variable, the memory pane displays the memory it 
occupies. See “Displaying Memory” below. 

Examining Structured Variables 

When you double-click on a variable in the variable display, LightsBug displays its expanded 
view in the middle pane. If the variable is a structured type (a record, an array, a set, or an object), 
LightsBug shows you all the fields of the record or all the elements of the array. For example, if you 
double-click on the value of a record, you’ll see all the fields of the record and their values in the 
expanded view pane. 

This is what the LightsBug window looks like if you double-click on the self variable in the 
variable display pane: 


M DraiuOneShap* 

JP TDrawU i ndow. Dollp 

- HandleUpdate 

j&k MainLoop 


■—ggj LightsBug-1 &\\; 

Procedure TShape.Draw 

True fill It 

- 

00241D88 fippleMenu 
00242678 Co I orflenu 


BooI eon 

JShgpe.... 


MenuHandIe 
MenuHandIe 


fShape<TFiIledRect) ♦ TShape.Draw ♦ ODTShape 


< record > boundingBox 
33 shapeCoI or 
1 shapePattern 


Rect 

Integer 

Integer 


Base: [EBjeErareal Q Offset: f0000| [Edit) 
T-TOOO: 1472 0010 0039 0042 00D7 0021 000 
X 010 : 8200 0014 0000 008C OOOfl 0000 000 

■—-020 : 010E 00R2 0000 0024 7FFF 0327 000 

])))[ 030: 7FFF 7FFF 0000 0014 0024 256C 000 

— 040: 0000 0000 0000 0000 8000 0080 000 

050: 1452 0024 4650 0024 261C 0024 261 


1472 

0010 

0039 

0042 

00D7 

0021 

0001 

0240 

.r...9.B.O 

_j_ 

8200 

0014 

0000 

008C 

OOOfl 

0000 

0000 

0064 

c. a.. 


010E 

0002 

0000 

0024 

7FFF 

0327 

0006 

0240 

...... .$0. 


7FFF 

7FFF 

0000 

0014 

0024 

256C 

OOOfl 

0000 

□□.$*l 

• • • 

0000 

0000 

0000 

0000 

8000 

0080 

0000 

OOflO 

. A. 

.A. . 

1452 

0024 

4650 

0024 

261C 

0024 

2614 

0024 

.R.$FP.$&. 

.$&. 


The top line in the expanded view gives you the name of the variable and its type. If the variable is 
an object, LightsBug displays it using its declared type and shows its runtime type in parentheses, 
as in the example above. If the variable is a handle or a pointer, LightsBug dereferences the vari¬ 
able to its base type. The top line also tells you the name of the routine and unit that your variable 
is defined in. 


Note: LightsBug dereferences generic handles and pointers as if they were of the 
type SignedBy te. If you know the type of the object a generic pointer or handle 


192 


























LightsBug 14 


refers to, you can use type coercion to display it. You can also use type coercion 
to display an object using its runtime type. See “Type Casting Variables” below. 

The fields of records appear in declaration order, and the elements of arrays appear in order. The 
expanded view displays values the same way as the variable display, so if a record contains 
another record, its value is <record>. 

Note: If an array has more than 32,000 elements, LightsBug displays only the first 
32,000 . The array has not been truncated. 

To see an expanded view of a field of a record, an element of an array, or a set, just double-click 
on it. The field or element’s expanded view replaces the current expanded view. 

LightsBug remembers each time you expand a value. You can use the arrow keys to follow the 
chain of expanded views. For example, suppose you’re looking at an event record in the expanded 
view. If you double-click on the where field of the event record, the expanded view displays it as a 
point. Pressing the Up or Left Arrow key would return you to the event record display. From there, 
pressing the Down or Right Arrow key would show you the point display. 

Note: You can also the < and > (or Command and Period) keys. Use the < (or 
Comma) key instead of the Left arrow and use the > (or Period) key instead of the 
Right Arrow. 


193 



THINK Pascal User Manual 


Examining Many Variables 

The expanded view lets you see only one variable at a time. To see several variables at a time, you 
can save them in the collected views. To put a variable in the collected views, just drag it from ei¬ 
ther variable display or the expanded view to the collected view icon®. When you click on the 
collected view icon, you’ll see all the variables in the middle pane. 


DrauiOneShape 
>???????? 
TDrawUindow.C 
Hand I allpdate 
hainLoop 
-OBJECTDR 


LightsBug-2 


5 

<record> 

growRect 


<array> 

00242658 

0024267C 

gShapeTable 
gUntit1edCount 
gUindowList 
PaletteHenu 

_ 

00242674 

PattemMenu 

m 

00242670 

UindowMenu 


_01 

Ftect J5[ 

Array lTool Type 1 bna 
Integer 
TList 

henuHandle 
HenuHandle 
henuHandI 


|SELF = TShape< TF iI IedRect> # TShape.Draw ♦ ODTShape 

<record> boundingBox : Rect 

33 shapeColor : Integer 

J_ shapePattern _; integer 


e. ^ 


gUindowList. I istData**101 .window' 
0 device 
< record > por tBits 
<record> portRect 
00241C94 visRgn 
00241C90 clipRgn 
<array> bkPat 
<array> fillPat 
<record> pnLoc 
<record> pnSize 
8 pnhode 
<array> pnPat 


GrafPort 
Integer 
Bithap 
Rect 

RgnHandIe 

RgnHandIe 

Pattern 

Pattern 

Point 

Point 

Integer 

Pattern 


* ODTShape 


Base: Q 


[1 0 0ffset: f0000l fEdTT] 


000 

010 

020 

030 


0000 0000 0008 0100 0101 0024 1C88 0024 
1C98 0024 1CC4 0800 2004 0024 ICAO 0024 
1C8C 0049 0024 2630 0033 6936 0000 0000 
0024 2600 4400 00A8 0024 256C 0000 F992 


...$. 6 .$ 

.6.$.f.. 

.a.i.$&o.3i6_ 

.$&.D. .».$*! . .or 


You can have global variables and variables from different procedures and functions in the col¬ 
lected view. As your program runs, variables that belong to some routines will go out of scope. 
When this happens, their entry in the collected view says no context. If your program enters 
that routine again, you’ll see their full values again. 


To remove a variable from the collected views, just click on the first line of the variable and drag it 
to the trash icon. 


Note: You can’t drag items out of the trash like you can in the Finder. 

Using Watchpoints 

The watchpoints container is just like the collected views container. The difference is that when¬ 
ever the value of a variable in the watchpoints container changes, THINK Pascal stops your pro¬ 
gram and displays a “thumbs down" next to the line where the change was detected. Usually, the 
“thumbs down" points to the line following the line that actually changed the value. 


To turn off the watchpoints feature, drag the watchpoints to the trash. 


194 











LightsBug 14 


Use watchpoints to debug strange behavior in your program. For instance, suppose you have a 
pointer that somehow ends up pointing to the wrong thing while your program is running. If you 
put the pointer in the watchpoints container, your program will stop at the statement that’s 
changing the value of the pointer. 

To make the watchpoints feature work, THINK Pascal has to look at all the values in the watch¬ 
points container after every statement to see if they’ve changed. This checking will make your pro¬ 
gram run significantly slower. When you drag a variable to the watchpoints container, THINK 
Pascal makes a copy of it. After each step, it compares the current value of the variable to the saved 
value. If you drag large variables to the watchpoints container (for instance, an array that takes up 
100K), you might find that THINK Pascal runs out of memory. 

Note: You can double-click on a value displayed in the watchpoints pane to see 
its expanded view. 

Editing Variables 

You can use LightsBug to change the values of variables. To change a value, drag the variable into 
the edit value icon $. You’ll see a dialog box like this: 


filllt 


jTrue 


| 


Current Ualue 


False 




Neui Ualue 


Inter a new ualue for the enumeration in 

Jthe ranqe False..True |( OK I 

| ^ —* 

*. [ Cancel ] 


Type the new value of the variable in the New Value field, click on the OK button. LightsBug will 
change the value if the new value falls within the legal range. 

Type Casting Variables 

LightsBug lets you look at objects of one type as if they were objects of another type. This opera¬ 
tion is called type casting. For example, Inside Macintosh defines a windowPtr as a pointer to a 
Graf Port instead of as pointer to a WindowRecord. To examine the WindowRecord fields of a 
variable declared as a WindowPtr, you need to type cast it. Type casting is also useful when you 
want to look at an object using its runtime type instead of its declared type. 


195 











THINK Pascal User Manual 


Note: Sometimes you cannot coerce an object to its runtime type because the def¬ 
inition of the runtime type is outside the scope of the function you’re debugging. 

To type cast a variable, drag it from the variable display or any view in the center pane to the type 
cast icon You’ll see a dialog box like this: 



Type the new type for the variable in the New Type field, and click OK. LightsBug changes the 
type to the new type and displays its expanded view. 

Note: When you type cast a variable, the type of the original variable doesn’t 
change. What changes is the way it’s displayed in the expanded view 

Examining Registers 

To display the values of the CPU registers, click on the register icon in the LightsBug window. 
The upper right pane becomes the register display. The values of the registers appear in the 
register display like this: 


□ 

m 

>???????? 

\ R0-00238Q38 D0-00000401 
— fl1-00321RE6 D1-00280000 

R2-00000000 02-00241C34 

O 

TDratvU i ndow. DoUp 

ijiji R3-00000000 D3-00000000 

jjjjsj 

A 

Hand 1ttUpdattt 

liii! R4-00242624 04-00000000 


11a i nLoop 

[> R5-00266E36 D5-00000000 

2 


If your Macintosh has either the MC68881 or MC68882 floating point unit, and you have the 
68881/68882 option on, the values of the floating point registers appear in the register display, too. 

When you select a register, the value of the register becomes the new Base for the memory display. 
(See “Displaying Memory” below.) Usually you’ll want to select register A 7 (the stack pointer) to 
see what’s on the stack. 


196 

























LightsBug 14 


Note: If you need to edit the values of the registers, use a low level debugger like 
Macsbug or TMON. Unless you know exactly what you’re doing, it’s not a good 
idea to change the values of the registers. Be careful. See “Examining Compiled 
Code” at the end of Chapter 9, “Debugging Programs.” 

Examining Heap Zones 

When you select the heap icon /&. in the LightsBug window, the upper right pane becomes the 
heap display. The heap display lets you examine the pointers and handles allocated in any heap 
zone. To learn about heap zones, see Inside Macintosh I, Chapter 3 and Inside Macintosh //, 
Chapter 2. 

The heap display looks like this. 


D 

>???????? 

TDrawU i ndow.DoUp 
HartdleUpdate 
fla i nLoop 

<> 

H Heap :| 0024256C1 

Free Prable Hnd Lck Pra Ptr 

0000R838 00000044 02B 003 002 57C. 

O 

A 

1 ?£: 

2 

*P 002425R8 OOOddlOO 
*P 002426B0 0000001C 

jilljl 

2 


The three buttons at the top of the pane let you choose which heap to display: 

Button Heap zone displayed 

S System heap 

A Application heap 

C Current heap 

You can also enter the address of a heap zone in the box next to the buttons. If you enter an 
address that’s not a heap zone or if the heap is damaged, LightsBug gives you an error message. 

Note: All values in the heap display are in hexadecimal. 

Unless you changed the heap zone with the Toolbox routine Set Zone, the current zone is the 
same as the application zone. 

Right under the heap zone buttons you’ll see a summary of what’s in the heap: 


Heading 

Meaning 

Free 

total size of all free objects in bytes 

Prgble 

total size of all purgeable objects in bytes 

Hnd 

number of handles allocated 

Lck 

number of locked handles 

Prg 

number of purgeable handles 

Ptr 

number of pointers allocated 


197 







THINK Pascal User Manual 


After the summary, every line in the heap display describes an item i n the heap. 

resource type 
I resource ID 

resource file reference number 


SMC) Heap : |lMIMIMwiMBBl 
H 001EC8 000010 2 KSUP 0000 002 
H 011920 00000R 0 
*P 018CR4 000054 
F 018D00 000004 

1 

handle attributes 
8 - locked 
4 - purgeable 

2 - resource 

size of block 

base address of block 

type of block 
H - handle 
P - pointer 
F - free block 

* = locked 

To see the contents of an item in the heap, click on it. Its contents will appear in the memory 
display. The next section tells you how the memory display works. 

Displaying Memory 

The bottom pane of the LightsBug window is the memory display. Memory appears in hexadec¬ 
imal starting at the memory location Base+OffseL An ASCII display of the same memory appears to 
the right of the hex display. 



Bqse. lBMBiaaE fcHl PH Offset : fOQQOl fEdlD 
000: 0024 2624 01D4 0000 0000 0026 64EA 0D00 

010: 4758 002S E1D4 0026 647E 0026 64BE 0025 

020: E9C2 0024 2624 0000 0000 0000 0000 0024 

030: 260C 0026 256C 0000 0000 0000 0000 0026 


1 

. ..&dD.. 

£ 

iPH 

i GX.XD‘.&d~.&d«.* 

iiiij 


.$ 

K> 

i &..&XI.. 

.& 

S3 


There are several ways you can choose which memory is displayed. They all involve changing the 
base address or the offset. 


198 











LightsBug 14 


To display a certain location in memory, type in its address in the Base field and press the Return or 
Enter key. You can also specify an offset in the Offset field. If you click on the + button, THINK 
Pascal adds the offset to the Base and resets the offset to zero. 

Note: You can press the - key to undo changes you made to the Base or Offset 
field. 

To display an item in the heap, click on it in the heap display pane. If the item is a pointer, the 
pointer becomes the Base address. If the item is a handle, the dereferenced handle becomes the 
Base address. The offset is set to zero. 

To display the memory a register points to, click on a register value in the register display pane. 

The value of the register becomes the Base address, and the offset is set to zero. 

To display the memory a variable occupies, click on a variable in the variable display pane or in 
any of the views in the center pane. The location in memory that holds the beginning of the 
variable becomes the Base address, and the offset is set to zero. 

To see the frame pointer for a subroutine or function, click on its name in the variable display 
pane. The address of the stack frame becomes the Base address, and the offset is set to zero. 

You can use the mouse to change the offset field. If you click on any byte in the memory display, it 
becomes the first byte displayed. The Base address doesn’t change, but the Offset is updated ac¬ 
cordingly. If you hold down the Shift key as you click on a byte in the memory display, the first 
byte in the display slides to the point you clicked on. 

You can dereference objects in memory. Click on a byte in memory as you hold down the appro¬ 
priate keys. Depending on the keys, THINK Pascal treats the four bytes after the cursor as either a 
pointer or a handle and shows you what it refers to. This chart shows you which keys to hold 
down: 

To deference a... Click on a byte as you hold down the... 

Pointer Option key 

Handle Option and Command keys 

THINK Pascal sets the Offset to zero. If you dereference a pointer , THINK Pascal sets the Base ad¬ 
dress to the four bytes after the cursor. If you dereference a handle, THINK Pascal sets the Base 
address to the address that the handle points to. 

LightsBug remembers the last eight changes to the base address. You can recall them with the < 
and > keys. 

Note: The offset field is sign extended (i.e. if you type in a minus sign followed by 
a hex number, it will compute the proper value). 


199 




THINK Pascal User Manual 


Editing Memory 

You can edit memory displayed in LightsBug. Be sure you know what you’re doing before you 
change any byte in memory. 

To edit memory, click on the small Edit button in the memory display pane or type Shift-E. A small 
window appears on top of the memory display: 

l-fl=lfllMili 1 £nter liCancel 1 1:36 

flddr: 00266478 FRexQ t Rever O C: . $ _ 

The Addr field displays the address of the memory you’re editing. Initially, this address is the same 
address as the base address of the memory display. 

The rectangles above the Addr field let you edit one, two, or four bytes at a time. The rectangles 
contain one, two, or four lines to indicate the number of bytes being edited. In this example the 
rectangle with two lines is selected, so the edit box displays the two bytes of memory starting at 
Addr. 

To edit memory just type a value in the box. When you are done typing you can click on any of the 
four buttons in the edit box: 

Button Action 

Enter This button causes the change to take effect This changes memory at Addr 

to the value just typed. You can also use the Return and Enter keys. 

Cancel This button cancels editing mode. You can also use Shift--. 

Next This button causes the change to take effect, and displays the next byte, 

word, or long word of memory. You can also use the Tab key. 

Revert This button restores the edited value to what it was previously. You can also 

use the - key. 

On the right side of the editing box, memory is displayed in different formats, with a letter identify¬ 
ing each format. Some formats may not be displayed depending on whether you’re editing one, 
two, or four bytes. 

Symbol Format 

C characters 

I integer 

L longint 

S signed byte 

U unsigned byte 

You can use the < and > keys to move through memory when you’re in edit mode. These keys 
change the offset in the memory display by one, two, or four bytes. 


200 





LightsBug 14 


Debugging Toolbox Routines 

LightsBug can also help you debug calls to Macintosh Toolbox routines. If you want to stop at ev¬ 
ery Toolbox call, choose the Break at A-Traps option in the Debug menu. When this option is on, 
your program will stop just before it executes a Macintosh Toolbox routine. When your program 
stops, it will look something like this: 


_ ODTShope.p 

procedure TShape.Fill (reallyFill: Boolean); 

var 

p: Pattern; 


m 


m 


begin 

F oreColorCshapeColor ); 

GetlndPatternCp, sysPatListID, shapePattern); 
PenPat(p); 


{ The 


10 


Break; 

jpfll _ 

THol lowRect.Fi I l| 

TFiIledRect.FiI I 
TShape.Draw 
DrawOneShape 

[Dra^^^ctrTabTor'to thi* flagni 


LightsBug-1 


A2-00000000 D2-00000000 
R3-00000000 D3-00000000 
R4-00242624 D4-00000000 
R5-00266E36 D5-00000000 
D6*00000001 
07 *00000000 

ying ^^s^^^TTo^see* 1 ^”expanded vi< 


R6-002663FR 


Base: | 
000 
010 
020 
030 
040 
050 


0 Offset:|0g00] [Edit! 
0000 0021 0024 2624 
0026 6424 1000 3B08 
0026 6424 0025 F92E 
2624 2624 0000 FFFF 
30F4 0025 F924 0026 
F9D8 0024 2624 00CE 


2624 0000 FFFF 7FFF 
0025 F556 0026 630E 
0024 2624 0024 0024 
FFFF 0026 644E 1000 
6408 0026 644E 0025 
0024 2624 0000 0000 


...!.$&$&$..ODD 
.&d$..;..SDU.tcO 
.&d$.S0..$&$.$.$ 
&$&$..□□□□.&dH.. 
-□.fO$.td..ftdH.S 
DQ.$&$.C.$&$.... 




A special execution finger with an A emblazoned on it points to the Toolbox routine your pro¬ 
gram’s about to execute. The LightsBug window shows you trap number in the subroutine call 
chain. 


LightsBug automatically chooses the register display and selects register A7 so you can see the con¬ 
tents of the stack in the memory display. In the example above, ForeColor takes as an argument 
an integer representing a color. The integer in this case is $21 (or 33 decimal). 

Note; If you are executing code that was compiled with the Debug option off, the 
special execution finger may point to the same statement for many distinct A-Trap 
breaks. 


201 




















Compiler Directives 

15 


Introduction 

This chapter describes the compiler directives you can use in your THINK Pascal programs and the 
options you can set to control code generation. A compiler directive is an instruction that tells the 
compiler how to compile a specific file or part of a file. 

You’ve already seen some of the THINK Pascal compiler directives as compiler options in the 
project window — the four letters D, N, V, and R. In this chapter you’ll learn more about what 
these directives do and how you can control them from within your source code. You’ll also learn 
about other directives that not only let you control how THINK Pascal compiles your source files 
but also what part of your source files it will compile. 

Topics covered In this chapter 

• What are compiler directives? 

• Using compiler directives 

• Using conditional compilation 

• Using the Compile Options command 



THINK Pascal User Manual 


What Are Compiler Directives? 

You’re already familiar with four compiler directives from Chapter 7. These are the four letters in 
boxes in the Options column of project window. These compiler options control code genera¬ 
tion for the file. When you add files to a project, the D and N options are already on. As you work 
on your program, you can turn the options on and off for specific files. 


=1-1= 

— 

— 

— 


m=l 

Options 

= ncnUUmp.TI = 
File (by build order) 

-- 

Size 

£ 





pRuntime.lib 

5980 

o 





Interface .lib 

10098 



D 

N 

V 

u 

globals.p 

0 



El 

E 

V 

IRJ 

utilities .p 

1260 



D 

N 

V 

s 

lines .p 

1712 



D 

N 

V 

n 

windows .p 

4562 



D 

N 

V 

1 

files .p 

978 



D 

N 

y 

11 

selection .p 

960 



D 

N 

y 

a 

goto.p 

996 



[0 

N 

V 

[El 

find.p 

3320 



[0 

N 

y 

e 

dump.p 

986 



D 

N 

V 

m 

main.p 

3454 



D 

N 

y 

m 

DA Shell 

2504 






rofj/Cotfc S/ir* 

36810 

o 

2l 






c> 

lal 


Option Meaning 

D Debug. Generates additional information between each Pascal statement to 

support stepping, stopping, and observing. 

N Names. Inserts the name of all routines into the code. This is useful for 

debugging with LightsBug or low-level debuggers. 

V Overflow Checking. Generates code that checks for integer arithmetic 

overflows. 

R Range Checking. Generates code that does range checking for array index¬ 

ing, assignments, and parameter passing. It also generates code that checks 
for nil pointer dereferencing. 

To disable an option, click on the appropriate letter. The box around the letter disappears. To en¬ 
able the option again, click on the letter. The box reappears. 

Note: If you hold down the Option key as you click on a compiler option, THINK 
Pascal will change the option for all the files in the project. 


204 





Compiler Directives 


15 


Using compiler directives In your source files 

You can also turn these compiler options on and off from your source file. When you use the com¬ 
piler options in your source files, they are called compiler directives because they direct the 
compiler to generate different code. In addition to the four directives you can set as compile 
options, THINK Pascal provides seven more. 

A compiler directive looks like this: 

{ $D+} 

A compiler directive is a comment that begins with a $. The text after the $ specifies which direc¬ 
tive and whether it’s on or off. In this example, D+ means that you want to turn the setting on. A 
minus sign would mean that you want the setting off. 

Note: There are no spaces between the { and the $. 


THINK Pascal supports these nine compiler directives: 


Directive 

{ $D+} or { $D-} 
{ $N+} or { $N-} 
{$N++} 

{$V+} or{$V-} 
{ $R+} or{$R-} 
{$1 + } or {$1-} 
{$J+} or{$J-} 
{ $Z+} or { $Z-} 
{$S name } 


Meaning 

Turns Debug option on or off 
Turns Names option on or off 
Turns Tracing and Names options on. 

Turns Overflow Checking option on or off 
Turns Range Checking option on or off 

Turns automatic initialization on or off (only in main program) 
Turns External Variable handling on or off. 

Turns External Routine handling on or off. 

Puts the following code into the segment name. 


Note: The MPW Pascal { $D±} directive corresponds to the THINK Pascal { $N±} 
directive, not the THINK Pascal { $D±} directive. Some MPW directives don’t have 
analogous directives in THINK Pascal. 


THINK Pascal also supports these two related directives: 

Directive Meaning 

{ $PUSH } Save the current settings of the D, N, V, J and Z compiler directives 

{ $POP } Restore the settings of the D, N, V, R, J and Z compiler directives 

from the previous { $PUSH}. 

Finally, THINK Pascal recognizes this directive when it prints a file: 

Directive Meaning 

{$p} Start printing on a new page. 

The first four directives — D, N, V, and R — correspond to the four compile options in the project 

window. The difference between the compiler options and the compiler directives is that the 


205 



THINK Pascal User Manual 


embedded compiler directives let you control code generation a t the procedural level or even the 
statement level. For example, one common technique is to turn off the Range Checking option 
when you want to change the length byte of string: 

{$R-} 

myString[0] := 0; { pretend it's a null string } 

To use a compiler directive, you put it right before the line you want to affect. That directive 
remains in affect until the end of the file or until you turn it off (or on) again. In the example above, 
the Range Checking option will remain off until the end of the file or until you turned it on again 
with { $R+}. 

If a compiler option — D, N, V, or R — is turned off for a file in your project, you can’t turn it back 
on with a compiler directive in your file. In other words, the compile options in the project work 
like a “master switch” for the compiler directives in your file. 

If you use the Debug, Name, External Routine, or Tracing directives, you must change their state 
before the first begin of a procedure or function, or they won’t have any effect until the next 
procedure or function. For example, to turn off debugging for a procedure, you’d write this: 

{$PUSH} 

{ $D-} 

{ Don't generate debugging code for this procedure } 
procedure SalmonSushi; 

begin 

end; 

{$POP} 

But this won’t work: 

procedure Pakora; 
begin 

{$PUSH} 

{$D-} 

end; 

{$POP} 

THINK Pascal will still generate debugging code for procedure Pakora. 

How compiler directives work 

When you turn on one of the D, N, V, or R compiler directives, THINK Pascal weaves “invisible” 
code into your program. For example, the D directive inserts code that lets THINK Pascal know 
what your program is doing, so you can use its powerful debugger. Other options, V and R, for in¬ 
stance, insert error checking routines to check for overflow or out-of-range conditions. When you 
turn on more than one option, you get the extra code for each option. 


206 



Compiler Directives 15 


When you change a compile option for a file, THINK Pascal recompiles the file to generate the new 
code before you run. 

Using Compiler Directives 

This section describes each compiler directive in detail. You’ll learn exactly what the directive does 
and when you should use it. Since every compiler directive generates extra code, you’ll also learn 
what it costs you — in terms of speed and memory — to use the directive. 

Debug{$D±} 

When you turn the Debug option on, THINK Pascal generates code that lets you use all of the 
THINK Pascal debugging features. This code makes it possible for THINK Pascal to display a 
thumbs-down icon next to an error that occurs while your program’s running. For example, if your 
program tries to divide by zero, or tries to write beyond the end of a file, or tries to assign an out- 
of-range value to a variable, the debugging code lets THINK Pascal know which file and which line 
contains the error. 

This directive also generates code that looks out to make sure your stack doesn’t collide with the 
heap. If the stack were to run into the heap, you’d get a System Error ID=28. The error would dam¬ 
age the THINK Pascal environment, and you’d have to reboot and start again. Typically, these 
errors are hard to track down. 

The debugging directive acts as a kind of safety net, so it’s a good idea to leave this option on while 
your program is still unstable. 

If you use the { $D±} directive in your source code, be sure to put it before the first begin of the 
procedure or function you want to affect. 

Cost The Debug directive increases your code size by about 30%. Your program 

runs 2 to 10 times slower. 

Limits You can’t have the Debug option on in a standalone application or in a li¬ 

brary. When you choose one of the Build... commands from the Project 
menu, THINK Pascal turns the Debug directive off automatically. 

Uses If you plan to use a low-level debugger like TMON or Macsbug to debug a 

piece of code, it’s best to turn the Debug directive off so the additional de¬ 
bugging code doesn’t get in your way when you look at the assembly 
language listing. 


Names ($N±) 

The Names directive embeds the subroutine name into the code right after the end of the proce¬ 
dure or function. LightsBug uses this name when the source file that contains the routine isn’t 
open. Other low-level debuggers like TMON or Macsbug use these names as well. 


207 



THINK Pascal User Manual 


THINK Pascal can store the names two ways, depending on how you set the Long names option: 

• If the Long names option is off, names are limited to eight uppercase characters. 
Underscores are stripped off. Names shorter than eight characters are padded with 
spaces. For methods (e.g., TDrawWindow. FileWrite), only the First eight characters 
of the class and method names are stored (e.g., TDRAWWIN. FILEWRIT). LightsBug, 
TMON, and all versions of Macsbug can use eight-character names. 

• If the Long names option is on, names can be any length, all uppercase. For methods 
(e.g., TDrawWindow. FileWrite), the full class and method names are stored (e.g., 
TDRAWWINDOW. FILEWRITE). LightsBug and Macsbug 6.0 and later can use full-length 
names. 

To see the Long names option, choose Compile Options... from the Project menu. For more 
information on that command, see “Using the Compile Options Command” at the end of this 
chapter 

Cost Up to 255 extra bytes per procedure or function. No speed penalty. 

Limits Eight-character names are limited to eight characters. Full-length names are 

limited to 254 characters. 

Uses Turn the Names option on whenever you’re using LightsBug, TMON, or 

Macsbug to help you find your way around your routines. It’s usually a 
good idea to turn this option off before you create your final release. 


Tracing ($N++) 

The Tracing {$N++ } directive is included for compatibility with MacApp. It lets you trace your 
procedures and functions with the MacApp debugger. The { $N++ } directive also turns on the 
Names option, since the MacApp debugger’s tracing routines print out function and procedure 
names. 


Note: MacApp turns on the Tracing and Names options automatically when you 
use the MacApp debugger. Most of the time, you won’t need to turn on the 
Tracing directive yourself. For more information on the MacApp debugger, see 
your MacApp documentation. 

If your project doesn’t use MacApp, you must define these procedures to do your own tracing: 


Declaration 
procedure %_BP ; 
procedure %_EP ; 
procedure %_EX; 


Description 

Called at the beginning of every procedure. 
Called at the end of every procedure. 

Called before an exit or a non-local goto. 


208 





Compiler Directives 


15 


To turn off the Tracing option, use either { $N+ } or { $N- }. The { $N+ } directive leaves the 
Names option on, and the { $N- } directive turns the Names option off. This chart summarizes what 
these directives do: 


This directive... turns the Names option... and the Tracing option... 

{ $N++ } On On 

{ $N+ } On Off 

{ $N- } Off Off 

Overflow {$V±} 

The Overflow directive generates code that detects errors resulting from numeric overflow in 
arithmetic operations. The result of each intermediate operation must be within the bounds of nu¬ 
merical representation. For type integer, the bounds are -32768 to +32767. For type longint, 
this range is -2147483648 to +2147483647. 

For example, consider this procedure: 

procedure Boom; 
var 

i, j, k : integer; 

begin 

i := 20000; 
j := 21000; 
k : = i + j ; 

end; 

You might expect that k = 410 00, but since the largest integer is 32767, k would overflow 
(-24536), and you’d have an error. If the Overflow directive is on, THINK Pascal will catch this kind 
of error. 

The Overflow directive doesn’t check floating point operations, but the SANE library does. The 
SANE environment lets you control the effects of overflow in floating point operations. See the 
Apple Numerics Manual, Second Edition to learn more about SANE. 

Cost Two extra bytes generated for every arithmetic expression. Your program 

runs 5% to 10% slower. 

Limits The Overflow works best while your program is still under development, 

and you’re still working in the THINK Pascal environment. You can exam¬ 
ine the variables that caused the overflow and correct their values in the 
Observe or LightsBug windows. In a standalone program, recovery is more 
difficult, if not impossible. 

Uses Use the Overflow directive to track down potential problems and to make 

sure that your program deals with errors appropriately. 


209 






THINK Pascal User Manual 


Range {$R±} 

The Range directive makes sure that values fall within legal bounds. For variable assignment, this 
directive checks that a value assigned to a variable is in the legal range for the variable. For in¬ 
stance, when your program assigns a value to a variable of type integer, it makes sure that the 
value falls in the range ±Maxint (-32768 to +32767). 

The Range directive also makes sure that the index of an array falls within the bounds of the index 
type. For instance, suppose your program contains this declaration: 

var 

SomeArray : array [1..25] of INTEGER 
The Range Checking directive would catch an illegal error like: 

SomeArray[27] := 1961; 

Note: If the index is a constant, the Range directive catches the error at compile 
time. Otherwise, it catches the error while the program is running. 

Strings are a special case. When the Range directive is on, it makes sure that the character being 
accessed is in the range of the string’s current length. For example: 

type 

s25 = string[25]; 

var 

MyString : s25; 

begin 

MyString := 'abc'; 

MyString[4] := x; { ERROR.} 

end; 

In fact, the most common use the of the { $R±) directive is to turn it off while your program ma¬ 
nipulates strings. For instance, if you wanted to write your own version of the predefined length 
function, you’d have to write it like this: 

{$PUSH} 

{$R-} 

function MyLength (s: string): integer; 
begin 

MyLength:= ord(s[0]); {Compiles ONLY if Range option is off} 

end; 

{$POP} 

For more information about how THINK Pascal deals with strings, see Sections 3.3 and 4.3.1 of 
Chapter 17. 

Finally, the Range directive checks to see if a pointer is nil before it dereferences it. The directive 
won’t keep you from dereferencing an odd or invalid pointer, though. 


210 



Compiler Directives 


15 


Cost Four to 24 bytes extra code generated for assignments, array accesses, and 

pointer dereferences. Your program runs about 10% to 20% slower. 

Limits Like Overflow checking, Range checking is easy to fix while you’re still in 

the THINK Pascal environment. Error recovery is difficult and impractical in 
standalone programs. 

Uses Turn the Range Checking directive on while your program is still under de¬ 

velopment. You’ll probably want to turn it off when you want to manipulate 
strings directly. 

Initialization {$l±} 

As mentioned in Chapter 12, THINK Pascal usually takes care of initializing all the Toolbox man¬ 
agers for you. You can use the Initialization directive to turn this feature off if you prefer to initial¬ 
ize the managers yourself. The { $1 +} directive tells THINK Pascal to initialize the managers auto¬ 
matically. The { $1-} directive lets THINK Pascal know that you’re going to handle the 
initializations. 

When the Initialization directive is on, THINK Pascal calls these Toolbox routines: 

InitGraf(@thePort); 

InitFonts; 

InitWindow; 

InitMenus; 

TEInit; 

InitDialogs (nil) ; 

SetApplLimit (value of A7 - value of Run Options... stack size) ; 

MaxApplZone; 
for i := 1 to 10 do 
MoreMasters; 

The { $ I -} directive should appear before the begin of your main program. THINK Pascal 
ignores this directive in units. 

Note: THINK Pascal never does automatic initialization for desk accessories, 
device drivers, or code resources. 

You’ll usually use the { $1-} directive when you port Pascal code that contains the Toolbox 
manager initializations. 

Note: You need to insert { $ I -} in most programs you port from other Macintosh 
compilers. 

If you checked the 68881/68882 option in the Compile Options... dialog, THINK Pascal also 
initializes the state of the MC68881 or MC68882 floating point unit (FPU). This means that if you 
want your application to check for a FPU, you should turn the Initialization directive off. Other¬ 
wise, your program will crash at startup on a machine that doesn’t have a FPU. To learn more 


211 



THINK Pascal User Manual 


about the 68881/68882 option, see “Using the Compile Options Command” at the end of this 
chapter. 

To initialize the FPU state yourself, use this procedure: 


procedure InitFPState; 

inline 

$42A7, { clr.l 

$42A7, { clr.l 

$F21F, $9800; { fmovem.l 


- (sp) 

-(sp) 

(sp)+, fpcr/fpsr 


1 

) 

} 


External Variable {$J±} 

The External Variable directive {J±} tells THINK Pascal not to allocate space for the following 
variables. Use it to access variables defined elsewhere, such as in a library or in an assembly 
language file. If you don’t define a variable elsewhere with the same name, you’ll get a link error. 
For example, this is the interface file fora library that declares the external variable ioStatus: 


unit io; 
interface 

{$PUSH} 

{$J+} 

var 

ioStatus: integer; 

{$POP} 


Note: At the end of the variable declaration section, you must turn off the External 
Variable directive (with either { $ J- } or { $POP}). 

You can also use the external variable directive to create libraries of objects. When THINK Pascal 
comes across a class declaration, it generates code to help resolve calls to its methods. Without the 
external variable directive, THINK Pascal generates this code twice: once in the library and again in 
the interface file. Use the external variable directive in the interface file to avoid generating the 
code a second time. For example, this class declaration will not generate it: 

type 

{$PUSH} 

{$J+} 

MyWindow = object (Window) 
windowData: Handle; 
subwindow: ToolWindow; 

procedure Hit (where: Point); 
overriden- 
procedure Draw; 
override 
end; 

{$POP} 


212 



Compiler Directives 


15 


External Routines {$Z±} 

The External Routine directive { $ Z±} makes the procedure or function that follows it externally 
visible. When a routine is externally visible, any unit in a project — even a unit that comes before 
the routine’s unit in the build order — can declare the routine as external and use it 

This directive is useful when you’re writing a large project that contains circular dependencies; for 
example, unit A requires a function in unit B which requires a function in unit A. If you’ve never 
come across a circular dependency, you should use a unit’s interface section to declare the 
functions and procedures that other units need. For more information on the interface section and 
the best way to write units, see Chapter 10, “Units and Libraries.’’ 

Push {$PUSH} and Pop {$POP} 

The Push directive saves the current settings of the D, N, V, R, J, and Z compiler directives. The Pop 
directive restores these settings. This lets you change the setting of a compiler directive for one or 
more routines, and then restore it to its original setting, without having to know the original setting. 
Here’s an example: 

{$PUSH} 

{$R-1 

procedure MyProc; 
begin 

end; 

{$POP} 

This turns off the Range Checking option for the procedure MyProc, and restores it to its original 
setting when the procedure is done. 

Segmentation {$S name} 

The Segmentation directive, {$S name }, places the code for all following procedures and func¬ 
tions (up to the next segmentation directive or the end of the file) into the segment name. This 
directive lets a single unit contribute code to several Macintosh segments. 

Note: Don’t use %_SelProcs or %_MethTables as segment names. They are 
reserved by THINK Pascal. 

Case is significant in segment names. For example, InitSeg and initseg are different segments. 

The linker places functions and procedures into the file’s segment if 

• no Segmentation directives appear before the routines 

• a { $S Main} directive is before the routines 

• a { $S} directive (with no segment name) is before the routines. 

Note: Don’t place a segmentation directive in a unit’s interface section. If you do, 
that will place the routines of any file that uses that unit into that segment. 

For more information on segmentation, see Chapter 7, “Working with Projects.” 


213 



THINK Pascal User Manual 


Page Break {$P} 

THINK Pascal recognizes the Page Break directive { $P} only when it’s printing a file. When it sees 
the directive, it starts printing on a new page. The Page Break directive is the first thing on the new 
page. 

Using Conditional Compilation 

The compiler directives described above let you control how THINK Pascal generates code in spe¬ 
cific instances. The conditional compilation directives, though, let you generate different code 
for different circumstances. For instance, while you’re debugging your application, you might want 
to have additional debugging menus or particular routines that help you see what your application 
is doing. Or you might want to create two versions of your application: one that runs on any 
Macintosh and another one that runs only on a Macintosh with a floating point processor. 

The four conditional compilation directives are: 

{$SETC identifier = expression] 

{ $IFC expression } 

{$ELSEC} 

{$ENDC} 

These compiler directives work like Pascal statements. An identifier can be any legal Pascal identi¬ 
fier. An expression can consist of identifiers, integer constants, boolean constants and these 
operators: DIV, MOD, =, <>, <=, >=, <, >, AND, OR, NOT. 

An expression can also be of the form UNDEFINED identifier. This expression evaluates to TRUE if 
the identifier is undefined and FALSE if the identifier is defined. 

To find out which compiler options are set, use the OPTION ( optionName) function. The argument 
can be one of MC68881, MC68020, DEBUG, RANGE, OVERFLOW, or NAMES. 

The { $SETC} directive lets you set values to compile-time variables. These are not variables that 
you can use in your program. Instead, you use the variables to define conditions. 

Note: You can use : = as well as = in a { $SETC } directive. 

By combining compile-time variables with the { $IFC}, { $ELSEC} , and { $ENDC } directives, you 
can tell THINK Pascal which parts of your program you want it to compile and which parts you 
want it to ignore in specific cases. 

Here’s an example. Suppose that you were writing an application that had a special menu that you 
wanted on only during development. You might write this: 


214 




Compiler Directives 


15 


program Toast; 

{$SETC development = TRUE} 

const 

FileMenuID = 1; 

{$IFC development} 
DebugMenuID = 7; 

{$ENDC} 


procedure StartMenus; 

var 

h : MenuHandle; 

begin 

{$IFC development} 

h := GetMenu(DebugMenuID); 
InsertMenu(h, 0) ; 

{$ENDC} 

end; 


Note: In an actual case, you would probably set the value of the compile-time 
variable development with the Compile Options... command described in the 
next section. 

You can use conditional compilation directives anywhere in your source file, even in constant and 
type declarations. If you use a { $SETC} directive in a unit, you’ll be able to use it in any file that 
uses the unit. 

Using the Compile Options... Command 

The Compile Options... command in the Project menu lets you predefine symbols that you can 
use for conditional compilation as well as set up some other code generation options. 


215 



THINK Pascal User Manual 


When you choose Compile Options. .. from the Project menu, you’ll see this dialog box: 


Compiler Uariables: 


THINK_PascaI = TRUE; 

THINK_PascaI _Uersion_4 = TRUE; 
EIems881 = TRUE; 



Cancel 


□ ‘USES’ Extensions 


Code Generation: 

□ 68020/68030 

□ 68881/68882 

□ Profile 


□ Large Sets 

□ Long Names 


Compiler variables 

You can define any compile-time variable in the text-edit box in the left side of the dialog just as if 
you had typed: 

{$SETC identifier = value) 

THINK Pascal predefines three compile-time variables for you, THINK_Pascal, 
THINK_Pascal_Version_4 and Elems881. Use the THINK_PASCAL compile-time variable 
when you need to know if your program is being compiled by THINK Pascal. Use the 
THINK_Pascal_Version_4 when you need to know whether your program is being compiled 
by the latest version of THINK Pascal. 

The Elems8 81 compile-time variable is used by the SANE . p interface file to indicate that it should 
use the faster (but less accurate) transcendental functions built into the MC68881 and MC68882 
floating point units if the 68881/68882 option is on. If you set the Elems881 compile-time variable 
to FALSE, THINK Pascal will use the slower, but more accurate, software versions of the tran¬ 
scendental functions. 


216 






Compiler Directives 


15 


USES Extensions 

If you turn on the “USES Extensions” option, THINK Pascal lets you use these features: 

• Propagated uses. If your unit uses other units, any unit that uses your unit also uses 
those units automatically. 

• Implementation uses. You can put a uses clause in a unit’s implementation section. 

For more information on these features, see “The uses clause,” in Chapter 10, “Units and Libraries.” 

68020/68030 option 

When the 68020/68030 option is on, THINK Pascal generates code that uses the MC68020 or 
MC68030 CPU found in some Macintosh models (the Macintosh SE/30, II, IIx, Ilex, and Ilci) and 
accelerator boards. If this option is on, your code will run only machines that have a MC68020 or 
MC68030. Specifically, THINK Pascal uses MC68020 and MC68030 instructions for 32 bit multiplies 
and divides and the RTD instruction to strip arguments off the stack. 

Note: THINK Pascal doesn’t check to see whether the machine you’re writing 
your program on or whether the machine your application runs on has a MC68020 
or MC68030. Use Gestalt Manager check the features of the Macintosh you’re 
program is running on. 

68881/68882 option 

The 68881/68882 option controls whether THINK Pascal generates code that directly calls the 
MC68881 or MC68882 floating point unit (FPU) for floating point operations. If this option is on, 
your code will run only on machines that have a FPU. 


Note: THINK Pascal doesn’t check to see whether the machine you’re writing 
your program on or whether the machine your application runs on has a FPU. If 
you aren’t sure that your program will always run on a Macintosh with a FPU, turn 
off automatic initialization with the {$1-} directive and use the Gestalt Manager to 
check the features of the Macintosh you’re program is running on. 

Using the 68881/68882 option and the Elems881 compile-time variable, described above, you can 
choose among three ways of handling floating-point operations. Choose an option depending on 
which of these are important to you: speed, accuracy, and portability. 


To make your program... 

Portable 

Fastest 

Fast and Accurate 


Turn 68881/68882... 

Off 

On 

On 


and set Elems881 to... 

true or false 

true 

false 


217 



THINK Pascal User Manual 


• Portable. U se this option for most programs, unless your program does a lot of intensive 
calculation and you can afford to have it run only on machines with a FPU. 

• Your program will run on all Macintosh models 

• Include SANELib. lib in your project. 

• All floating-point operations use the SANE library. If a FPU is present, the SANE library 
will use it. 

• All functions comply with the SANE accuracy standards. 

• All variables declared extended are 80 bits long. 

• Fastest. Use this option for programs that do a lot of intensive calculation and that need to run 
only on machines with a FPU. 

• Your program will run only on Macintosh models with a FPU. 

• You don’t need to include a special library. 

• All floating-point operations call the FPU directly. 

• Most functions comply with the SANE accuracy standards. The transcendental functions 
(e.g., arc tan, exp, In) comply with the IEEE accuracy standards. 

• All variables declared extended are 96 bits long. 

• Fast and Accurate. Use this option for programs that do a lot of intensive calculation and need 
to be as accurate as possible. 

• Your program will run only on Macintoshes with a FPU. 

• Include SANELib 8 81 . lib in your project. 

• Most floating-point operations call the FPU directly. The transcendental functions (e.g., 
a ret an, exp, In) call the more accurate and slower routines in the SANE library. 

• All functions comply with the SANE accuracy standards. 

• All variables declared extended are 96 bits long. 

Note: The FPU’s built-in routines for the transcendental functions comply with 
IEEE accuracy standards, so they should be adequate in most cases. The library 
routines that comply with SANE’s more stringent standards can run over 100 times 
slower. For more information on SANE, see Apple Numerics Manual, Second 
Edition (Addison-Wesley). 

If your program doesn’t use all the math functions available in THINK Pascal, you may not need to 
include the library listed for your option. This table lists exactly which library you need, depending 
on the option you choose and the functions you use. If the space for a library contains “n/a,” that 
function is not available for that choice. If the space fora library contains “buit-in,” that version of 
the function is built into THINK Pascal, and you don’t need to include a library to use it 


To use... 

Include the library for the option you chose... 


Portable 

Fastest 

Fast and Accurate 

arccos 

n/a 

built-in 

built-in 

arcsin 

n/a 

built-in 

built-in 

arctan 

Runtime.lib 

built-in 

SANELib881.lib 

arctanh 

n/a 

built-in 

built-in 

cos 

Runtime.lib 

built-in 

SANELib8 81.lib 





Compiler Directives 


15 


To use... Include the library for the option you chose... 



Portable 

Fastest 

Fast and Accurate 

cosh 

n/a 

built-in 

built-in 

exp 

Runtime.lib 

built-in 

SANELib881.lib 

expl 

SANELib.lib 

built-in 

SANELib881.lib 

exp2 

SANELib.lib 

built-in 

SANELib881.lib 

explO 

n/a 

built-in 

built-in 

In 

Runtime.lib 

built-in 

SANELib881.lib 

lnl 

SANELib.lib 

built-in 

SANELib881.lib 

log2 

SANELib.lib 

built-in 

SANELib881.lib 

loglO 

n/a 

built-in 

built-in 

round 

Runtime.lib 

Runtime.lib 

Runtime.lib 

sin 

Runtime.lib 

built-in 

SANELib881.lib 

sinh 

n/a 

built-in 

built-in 

sqrt 

Runtime.lib 

built-in 

built-in 

tan 

SANELib.lib 

built-in 

SANELib881.lib 

tanh 

n/a 

built-in 

built-in 

trunc 

Runtime.lib 

Runtime.lib 

Runtime.lib 


Large sets option 

THINK Pascal lets you specify whether sets of integer include all integers (-32768 . . 32767) or 
just the range 0 . .255. Most of the time, you’ll use the smaller set range. The larger set range takes 
up considerably more space in your program and takes much longer to access than the smaller 
range. Sets of the range 0. .255 can take up at most 32 bytes. Sets of the range-32768 . .327 67 
can take up to 8192 bytes. 

Long names option 

When the Names option is on, THINK Pascal embeds subroutine names into the code right after 
the end of the procedure or function. Debuggers such as LightsBug, Macsbug, and TMON use these 
names. In the Compile Options... dialog, you choose how THINK Pascal stores them: 

If this option is... Names can be 

Off Only eight characters long 

On Any length 

Note: You can turn on the names option in the project window or with the names 
directive { $N+ }. See “Using Compiler Directives” above for more information. 

Profile option 

When the Profile option, THINK Pascal profiles your code. It collects statistics about your program, 
including the time spent in each routine. For more information, see Chapter 19, “The Profiler.” 


219 





THINK Pascal" 

PART FOUR 

Reference 

16 THINK Pascal Menus 

17 Language Reference 





THINK Pascal Menus 

16 


Introduction 

This chapter describes each of the THINK Pascal menu commands. It is organized by menu, from 
left to right along the menu bar. Within each menu, commands are described in the order in which 
they appear. 

The Apple Menu 

The Apple menu gives you information on THINK Pascal and contains your desk accessories (or 
the items in your Apple menu folder under System 7.0). 


Rbout THINK Pascal... 


The Apple menu 
About THINK Pascal... 

This command tells you what version of THINK Pascal you’re using. Click the mouse once to see 
the credits for THINK Pascal and click the mouse again to end the display. 




THINK Pascal User Manual 


The File Menu 

Use the File menu commands to work with files that you open and edit with the THINK Pascal edi¬ 
tor. This menu also has commands that let you launch other applications and that let you quit 
THINK Pascal. When you hold the Option key down, the File menu has commands to close and 
save all the open files, and to print all the files in the open project. 


File File 


Neui 

96N 

Open... 

960 

Close Rll 

9610 

Saue Rll 

Saue Rs... 

96S 

Saue a Copy Rs... 
Reuert 


Page Setup... 
Print Rll Files 

96P 

Delete... 

Transfer... 

Quit 

96Q 


Neui 

96N 

Open... 

960 

Close 

96111 

Saue 

Saue Rs... 

96S 

Saue a Copy Rs... 
Reuert 


Page Setup... 
Print... 

96P 

Delete... 

Transfer... 

Quit 

96Q 


The File menu 


The Option File menu 


New 

This command opens a new Untitled Pascal edit window. Use the Save As... command to save 
new files. 

Open... 

This command lets you open an existing Pascal file in an edit window. You can have up to 1 6 files 
open at once. You can also use this command to open Instant and Observe windows that you’ve 
saved. 

Close 
Close All 

The Close command lets you close the active window. Clicking in the window’s close box does 
the same thing. If you try to close an edit window, and the file has been modified since it was last 
saved, THINK Pascal asks you if you want to save the changes, discard them, or cancel the Close 
command. 

Note: When you hold down the Command key and click in an editing window’s 
close box, THINK Pascal hides the window without closing the file. 


224 










THINK Pascal Menus 


16 


The Close All command lets you close all the open files. To see this command, hold down the 
Option key and choose the File menu. 

Note: When you hold down the Option key and click in an editing window’s 
close box, THINK Pascal closes all the editing windows. When you hold down the 
Command and Option keys and click in an editing window’s close box, THINK 
Pascal hides all the editing windows without closing the files. 

Neither of these commands close the project window. Use the Close Project command in the 
Project menu to do that. 

Save 
Save All 

The Save command saves the file in the active edit window to disk. This command is dimmed if the 
current edit window is untitled or hasn’t been changed. 

The Save All command saves the files in all the open windows to disk. To see this command, hold 
down the Option key and choose the File menu. 

Save As... 

This command lets you save the current file under another name. I f you have made changes i n the 
current session, THINK Pascal saves them under the new name. The original file remains un¬ 
changed, and as you continue editing, you are editing the new file. This feature is useful for 
switching to a new version of a file, leaving the old file as a backup. 

The Save As... command tries to preserve the tie between the file you’re editing and its entry in the 
project window. If the file is in the project window, THINK Pascal changes the name of the file in 
the project window to the new name. This command won’t let you overwrite a file that’s already in 
the project window. 


225 




THINK Pascal User Manual 


When you choose this command, you’ll see a standard save dialog box with two additional radio 
buttons. When you choose Text Only, THINK Pascal saves the file as a text file that you can open 
with any text editor or word processor. When you choose Entire Document, THINK Pascal saves 
the file in a special format that loads faster and preserves any Stop signs you’ve set in the file. 


| <S) Object Dram Folder | 


Q About... Pk birt'S 

5 

d m<iki(jimu.p 


D CmbedOefProc.p 

a 

D Wrmw.iT 

: r, 

D (lbjo< tOrttMJ.p 

LI 

D tOrttw.ttsx 



Saue 'Untitled 1' as 
ODExtras.p 

©Text Only 
O Entire Document 


6=1 Moose 

[ J 

[ Driue ] 

[ Saue ] 
[ Cancel ] 


You can use Save As... to save the Instant and Observe windows to a file. When either of those 
windows is the active window, you can use the Save As... command to save them. 

Save a Copy As... 

Unlike Save As..., this command does not affect the status of the file currently being edited; it 
simply snapshots it to another file. This is a good way to make backups without finding yourself 
editing the backup. Save a Copy As... doesn’t let you overwrite a file that’s already in the project 
window. 

Revert 

This command restores the last-saved version of the current file, discarding any edits made since 
the last Save or Save As.... 

Page Setup... 

This command displays the standard Page Setup dialog that lets you specify the size of the paper 
you’re printing on, and whether the file should be printed upright on the page (tall orientation) or 
sideways (wide orientation). See your Macintosh owner’s manual for details. 

Print... 

Print All Files 

The Print... command lets you print the current file. The standard Print dialog box lets you set the 
page range among other options. When you press the OK button, your file begins to print. Each 
page of the file has a header showing the name of the file and the last modification date. To cancel 
printing, press Command-Period. 


226 





THINK Pascal Menus 


16 


Note: If the active window is the project window, the Print... command prints 
the project window. 

The Print All Files command lets you print the all the files in your project. You’ll see a dialog list¬ 
ing your files as it prints them. To see this command, hold down the Option key and choose the 
File menu. 

Note: The Print All Files command doesn’t show you the Print dialog, but uses 
the default settings for its options. 


Delete... 

This command lets you delete a file from your disk without leaving THINK Pascal. 


Transfer... 

This command lets you launch another application without first returning to the Finder. When 
you're running under MultiFinder, this command launches applications without quitting THINK 
Pascal. When you’re running under the Finder, holding down the shift key and selecting 
Transfer... launches an application and returns to THINK Pascal when the application exits. 

Quit 

This command quits THINK Pascal and returns to the Finder. 

If you choose Quit while a project is open, it is automatically closed. If any editing windows have 
been modified, THINK Pascal asks if you want to save or discard your edits, or cancel the Quit 
command. 


227 




THINK Pascal User Manual 


The Edit Menu 

The Edit menu has the standard Macintosh editing commands (Cut, Copy, Paste) as well as com¬ 
mands that let you specify how THINK Pascal should format your Pascal source files. 



Undo 

962 

Cut 

96H 

Copy 

96C 

Paste 

96U 

Clear 


Select Rll 



Show Clipboard 


Source Options... 
v'Ruto-Reformat 
Projector Rware 


The Edit menu 


Undo 

The Undo command reverses the last edit operation. The actual name of this command changes to 
let you know exactly which operation you’ll be undoing. After a paste, for instance, the name of 
this command changes to Undo Paste. Once you’ve undone something, the name of this 
command changes to Redo. 

If there isn’t anything to undo, this command is dimmed. If the operation to undo doesn’t belong to 
the frontmost window, the name of the command indicates that there is something to do, but the 
command is dimmed. 

You can’t undo a Replace All, or a Revert. 

Cut 

This command removes selected text and places it in the Clipboard. It replaces the current contents 
of the Clipboard (if there are any). Use the Paste command to insert text from the Clipboard into 
your file at the insertion point. 

Copy 

This command copies the selected text and places it in the Clipboard. The copy can be pasted 
somewhere else using the Paste command. 


228 


Paste 

This command copies the contents of the Clipboard into the file being edited at the insertion point. 
If text is currently selected, it is replaced. 






THINK Pascal Menus 


16 


Clear 

This command clears the selected text. The selection is not placed on the Clipboard. The Clear key 
on your keyboard has the same effect as the Clear command. 

Select All 

This command selects all the text in the current edit window. 


Show Clipboard 

This command shows you the contents of the Clipboard . 

Source Options... 

The Source Options... command lets you change the way the THINK Pascal editor pretty-prints 
your source code. You can also change the tab spacing, the indentation spacing, and the font that 
the editor uses to display your file. 

The four icons along the left let you choose different aspects of the formatting you can change with 
this command. When you click on the OK button, any changes you made in any section of this dia¬ 
log applies to your project. Clicking on the Save Settings button saves the settings as the THINK 
Pascal defaults. 


FONTS 

Lets you choose the font used to display your source 
code. 

The pop-up menus lets you choose the font and size 
that THINK Pascal uses to display your source file. 



KEYWORDS 

Lets you choose how THINK Pascal displays Pascal 
reserved words like begin and end. 



229 



THINK Pascal User Manual 


The case of the keywords can be one of these: 

Lowercase begin. . . end, for example. 
Uppercase BEGIN. .. END, for example. 
Mixed Case Begin. . . End, for example. 

And the style of the keywords can be one of these: 


Boldfaced 
Underlined 
Plain Text 


begin. . . end, for example. 
begin . . . end , for example, 
begin. . .end, for example. 


The most common keyword styles are lowercase bold, uppercase plain, and lowercase underline. 


INDENTATION 

Lets you choose the indentation style that THINK 
Pascal uses to pretty-print your program. 




Source Display Settings 


* 



B BEGIN starts a new line 



B Indent BEGIN/END within statements 


If 

B Indent statements within BEGIN/END 

K^vordt 

! 

□ Outdent declarations 

n 

■ 

Indent: It 1 spaces 

■ - 


Tabs at: |2 | spaces 


r 



_ 

( OK ] [Saue Settings] ( Cancel ] 


BEGIN starts a The reserved word begin appears at the beginning of a new line. When this 
new line option is off, begin appears at the end of a line. This is what your code looks 

like when you don’t check this option: 
for i := 1 to 10 do begin 

end; 


Indent 

BEGIN/END 

within 

statements 


If this option is checked, begin/end pairs are indented like this: 
for i := 1 to 10 do 
begin 

end; 


If this option is not checked, they’re indented like this: 
for i := 1 to 10 do 
begin 

end; 


230 




THINK Pascal Menus 


16 


Indent 

statements 

within 

BEGIN/END 


Outdent 

declarations 


Indent: 
Tabs at: 


This option controls whether statements within a begin/end pair are indented 
or lined up with the begin/end pair. Here’s what code looks like when this 
option is checked: 

begin 

writeln (i) ; 

end; 

Here’s what code looks like when the option isn’t checked: 

begin 

writeln(i); 

end; 


This option controls whether the const, type, and var declarations in pro¬ 
gram, procedure, or function declarations should be indented or lined up with 
the begin/end pair. This is what outdented declarations look like: 
program Outdent; 

procedure Delicate; 
var 

aVar : aType; 

begin 

end; 

begin 

end. 

And this is what code looks like with outdented declarations off: 
program NoOutdent; 

procedure Delicate; 
var 

aVar : aType; 

begin 

end; 

begin 

end. 

This is how many spaces added to the front of a line each time it’s indented. 
This is how many spaces are inserted when you press the Tab key. 


231 



THINK Pascal User Manual 


PARAMETERS 

Lets you choose how THINK Pascal displays 
parameter lists. 


list formal This is how a parameter list looks like with this option on: 

parameters procedure foo (a: integer; b: integer; c: integer); 

horizontally 



List formal 
parameters 
vertically 


This how a parameter list looks like with this option on: 
procedure foo (a: integer; 
b: integer; 
c: integer); 


Auto-Reformat 

This command lets you specify when THINK Pascal pretty-prints your program. This option is ini¬ 
tially checked, and THINK Pascal reformats your program every time you press the Return key or 
the semicolon (;) key. If you uncheck this option, THINK Pascal pretty-prints your program only 
when you press the Enter key or when you move the insertion point to another line. 

Projector Aware 

This option lets you work on a large project with people who use MPW Projector. When you select 
this option, THINK Pascal displays an icon in the lower-left-hand corner of every editing window 
that tells you whether Projector marked the file as read-only. If the file is not read-only, its window 
has a pencil icon. If the file is read-only, its window has a crossed-out pencil icon. For more 
information, see “Using MPW Projector with THINK Pascal” in Chapter 6. 


232 





THINK Pascal Menus 


16 


The Search Menu 

The commands in the Search menu let you find and replace strings in your source files. THINK 
Pascal also lets you search all the files in your project for a string. When you hold down the Option 
key, you can use a command that lets you search through your project’s files quicker. 



Find... 

36F 

Find Rgain 

3§n 

Find in nil Files 

3§T 

Enter Selection 

9§E 

Replace 

9§R 

Replace and Find Rgain 

S8D 

Replace Rll 


Shorn Selection 

Show Error 


Find... 

XF 

Find Rgain 

9§n 

Find In Nent File 

38T 

Enter Selection 

§§E 

Replace 

8§n 

Replace and Find Rgain 

XD 

Replace All 


Show Selection 

Show Error 


The Search menu The Option Search menu 


Find... 

This command lets you specify the string to search for. If the string is found, THINK Pascal 
highlights it. If it’s not found, you’ll hear a beep. 

At the start of an editing session, only the Find... command is active. The dialog box that appears 
when you choose this command lets you specify the search string as well as the replacement string: 


Search for 


HandleScroll 

[f FiSd 1 

( Don't Find ] 

Replace with 


f Cancel ] 



H UJhole UJords 

□ Match Case 

□ Multi-File Search... 


The two check boxes on the left let you specify how the editor looks for your string. 


233 








THINK Pascal User Manual 


If you check this option, the search matches your string only with whole 
words. If you uncheck this option, the search matches even if your 
string is embedded in another string. For example, if the Whole Words 
option is off, the search string rect matches rect, rectangle, and 
myrect. If the Whole Words option is on, the search string rect 
matches only rect. 

If you uncheck this option, the search treats uppercase and lowercase 
letters as if they were the same. If you check this option, the search 
matches only if the string matches exactly. For example, if the Match 
Case box is off, the search string rect matches rect, Rect, and 
RECT. If the Match Case box is on, the search string rect matches only 
rect. 

Note: Turning on the Whole Words option speeds up your search substantially . 

The Multi-File Search check box lets you look for the search string in all the source files in your 
project See Chapter 6 and the description for the Find in Next File command for more 
information about searching through more than one file. 

In addition to the Find button (“Go ahead with the search”) and the Cancel button (“Pretend I 
never invoked this command”), there is a Don’t Find button. Clicking on this button sets up the 
search and replacement strings without actually doing the search. The Don’t Find button is useful 
for setting things up for a Replace All... command. 

Find Again 

This command searches for the next occurrence of a previously specified string. 

Find In Next File 
Find In All Files 

These commands let you search for a string through more than one file. To use these commands, 
you must check the Multi-File Search check box in the Find... dialog. 

The Find in Next File command looks for the string specified in the Find... dialog box through 
each of the files in your project. If it finds the strings, THINK Pascal opens an edit window contain¬ 
ing the file, and selects the search string. At this point, you can go on and make any edits you 
choose. If you want to search further in the current file, you can use the Find Again, Replace, and 
Replace All commands, which work within the current file. When you’re ready to go on with the 
multi-file search, use the Find in Next File command. 

Using the Find in All Files command is like selecting the Find in Next File command repeatedly. 
To see Find in All Files, hold down the Option key as you select the Search menu. Like Find in 
Next File, Find in All Files looks for your search string through each file in your project. 
However, when Find in All Files finds your search string, it opens an edit window containing the 
file and continues searching in the next file in your project. Find in All Files stops only after it’s 
searched each file in your project. 


Whole Words 


Match Case 


234 



THINK Pascal Menus 


16 


Multi-file search is useful when you are writing a program, and decide to modify a routine that is 
used in several files. You can open each of the files containing the search string, so you can switch 
back and forth between the various edit windows as necessary. (This feature is also helpful when 
you are tracking down link errors due to undefined or multiply defined symbols.) 

Enter Selection 

This command sets the search string to the current selection. You can then use Find Again to be¬ 
gin searching, or Find... to set search options. This command clears Multi-File Search if it was set. 

Replace 

This command replaces the current selection with a replacement string. If you haven’t provided a 
replacement string, this command is dimmed. 

Replace and Find Again 

This command replaces the current selection with the replacement string, then finds the next in¬ 
stance of the search string, but does not replace it. Use this command to step through a series of 
replacements. After each replacement, you see the next instance of the search string, so you can 
decide whether you want to replace it. If you want to replace the string, use the Replace or 
Replace and Find Again commands. If not, use the Find Again command to find the next 
occurrence of the string. 

If you haven’t provided a replacement string, this command is dimmed. 

Replace All 

This command replaces every instance of the search string from the current cursor position to the 
end of the file. Use this command when you don’t want to give your approval for every 
replacement 

Note: Be careful with this command. You cannot undo it with the Undo 
command. 

Show Selection 

This command lets you get back to the insertion point or the beginning of the current selection if 
you’ve scrolled away from it. 

Show Error 

This command lets you see where THINK Pascal has detected an error in your program if you’ve 
scrolled away from it. 


235 




THINK Pascal User Manual 


The Project Menu 

The commands in the Project menu work with the current project. You can open and create pro¬ 
jects, set the project type, make sure all the files in the project are compiled and loaded. This menu 
also contains the commands you use when you’re ready to build a file containing your application, 
desk accessory, device driver, or code resource. When you hold down the Option key, this menu 
lets you add several files at once. 


Project 


New Project... 

Open Project... 960 
Close Project 


Odd “Utils.p” 

Odd File... 

Remoue 

Build Library... 
Build Application... 
Remoue Objects 


Set Project Type... 
Compile Options... 
Uiew Options... 


Get Info... 


Project 


New Project... 

Open Project... 960 
Close Project 


Rdd “Utils.p” 
Rdd Files... 
Remoue 


Build Library... 
Build Application... 
Remoue Objects 


Set Project Type... 
Compile Options... 
Uiew Options... 


Get Info... 


The Project menu 


The Option Project Menu 


New Project... 

This command creates a new project document and opens an empty project window. The project 
window includes entries for the default libraries Runtime. lib and Interface. lib. You can 
then add files to the project with the Add File... or Add Window commands. Only one project 
can be open at a time. 


Open Project... 

This command opens an existing project. 


Close Project 

This command closes the current project. If a project still has open files that haven’t been saved, 
THINK Pascal asks you if you want to save the files before closing the project. 


Note: When you click in the project window’s close box, THINK Pascal hides the 
project window without closing the project. To close the project, use this 
command or hold down the Command key when you click in the project 
window’s close box. 


236 






THINK Pascal Menus 


16 


When you close a project, THINK Pascal lets you open another project. If you don’t want to open 
another project, click on the Cancel button. 

Add “Utlls.p” 

This command adds the current THINK Pascal edit window to the project. If the current edit 
window is an Untitled window, THINK Pascal asks you to save the file first. The command name 
contains the name of the current edit window. 

Add File... 

Add Files... 

The Add File... command adds one file to your project. It displays a standard file dialog. Select the 
file you want to add, and click on the Add... button. After THINK Pascal adds the file to the project, 
it lets you choose another file to add. When you’re done adding files, click on the Done button. 

The Add Files... command lets you add several files to your project at once. To see Add Files..., 
hold down the Option key as you select the Project menu. You’ll see a dialog box like this: 


€5) Interfaces! 


1II III 11 ^■ 

> i=>Rkbar 

D Picker.p 

□ PictUtil.p 

D Pouier.p 

D PPCToolBox.p 

D PrintTraps.p 

□ Processes.p 

D Profile.p < 

( 1 

ill [ Driue ] 

. 

[ Done ] 

> [ Cancel ] 

. 

“. 

PrintCalls.Lib < 

>] ir 111 ' * 


- Il Add g 

Printing.p 

Script.p 

f Rdd Rll ] 

Objlntf.p 


< 

> [ R«rn«i»e ] 


The top list displays the contents of the folder you’re in. The bottom list displays the files that will 
be added to your project when you click Done. You add files to the bottom list with these 
commands: 

• To add a file, select it and click Add, or double-click on the file name. 

• To add all the files from the folder you’re in, click Add All. 

• To open a folder, select it and click Open, or double-click on the file name. (Add 
becomes Open when you click on a folder.) 

• To remove a file from the bottom list, select it and click Remove. 

• When you finish selecting files to add, click Done. 

• If you change your mind and don’t want to add any files, click Cancel. 


237 


















THINK Pascal User Manual 


The Add File. .. and Add Files... commands let you add add four kinds of files to your project: 

• THINK Pascal source files 

• THINK Pascal libraries 

• THINK C libraries 

• Macintosh Programmer’s Workshop object files (. o files) 

Remove 

This command lets you remove the selected source file or library from the project. It’s especially 
useful if you’re project is corrupted. For more information, see “Recovering Corrupted Projects,” in 
Chapter 7, “Working with Projects." 

Build Library... 

This command saves the current project as a library that you can add to other projects. A dialog box 
prompts you for the name of the library file By convention, library files end in . Lib, but any valid 
file name is OK. 

To learn how to create libraries, see Chapter 10. 

Build Application... 

Build Desk Accessory... 

Build Driver... 

Build Code Resource 

This command saves the current project as an application, desk accessory, device driver, or code 
resource. A dialog box lets you name the resulting file: 


^ Rpplications | 




<> 

czDTess 

[ J 

[ Ui'li'e ] 

Saue Rpplication as [ Saue ] 


RboutBoif 1.0d23 

[ Cancel ] | 

S Smart Link 


If the Smart Link option is checked, THINK Pascal uses only the referenced object code of the 
source and libraries to create the resulting file. It takes a little longer to put the application or re¬ 
source together, but the resulting file is as small as possible. Uncheck this option if you’re building 
frequently for testing. 

When THINK Pascal builds your project with one of these commands, it merges the resource from 
the resource file you specified in the Run Options... dialog box into the resulting file. 


238 





THINK Pascal Menus 


16 


Remove Objects 

This command removes all the compiled code from a project. All source files must be recompiled, 
and all libraries must be reloaded. 

Use the Remove Objects command when you need to make the project document as small as 
possible for archiving or for transmitting to someone else. 

Set Project Type... 

This command lets you set the project type. The default project type is Application, but you can 
change it to Desk Accessory, Driver, or Code Resource. All project types let you specify the file type 
and creator of the file created by one of the Build... commands. To learn the details of each project 
type, see Chapter 12. 

Note: It’s best to set the project type before you compile any of your source files. 

THINK Pascal needs to recompile all your source files if you change the project 
type once there is compiled code in the project. 

APPLICATION 

The Application presets the type 
to APPL and lets you fill in the 
creator. 



Bundle Bit If this option is on, THINK Pascal sets the bundle bit in the resulting file when 

you use one of the Build... commands. The bundle bit lets the Finder know that 
the file contains a BNDL resource, which is used to display the application’s 
icons. 

Far Code If this option is off, THINK Pascal lets you write large applications: applications 

with a jump table as large as 256 k. If this option is off, your jump table can be 
only 32K . The jump table includes an entry for every routine that your program 
calls from another segment or takes the address of. For more information, see 
“Building applications with large jump tables” in Chapter 12, “Building Projects.” 


Note: For more information on how the Finder uses the BNDL resource, see 
Chapter 7 of the Resource Utilities Manual. 


239 




THINK Pascal User Manual 


DESK ACCESSORY 
DRIVER 

The Desk Accessory and Device 
Driver dialogs are similar. For 
desk accessories, THINK Pascal 
presets the file type and creator 
so the resulting file is a Font/DA 
Mover file. There are other dif¬ 
ferences between desk 
accessories and device drivers. 
See Chapter 12 for details. 





Apphottion 

_ _ _ _ _, □ Bundle Bit 

Type: |DFIL | Creator |DM0U | n Fa, Code 





p Resource Information 


b^Iki 

Name:| | 

s 

Dr+**r 

El 

Cod* RtMiret 

Type: |DRUR j ID: 112 | Attribute*: ^ j qq ( 

□ Multi-Segment □ Custom Header 

Segment Type: | J 




Flags: ^|0400 | Delay: |o | 

I « ll 

Mask: ^sl[ot6R | 

[ Cancel ] 



— File Information- 




ri Bundle Rlt 


Type: |??7? | Creator: |??7? | , 

□ Far Code 







— Resource Information- 


9H 

Nome:[ | 


Dtsk Ac©#* tory 

Type: |DRUR 110: [o | Attributes: ^ [oo] 


m. 

□ Multi-Segment □ Custom Hemli'r 


fis 

Segment Type: [ J 

... 


lenl 

|— Driver Information- 


E_J 

Flogs: g|4F00 | Oelay: |o f 


J 

Cod* Rttourc* 

Mask: 0000 j 

f Cancel ] 





Name This field is the name of your desk accessory or device driver. By convention, 

desk accessory names begin with a null byte and device driver names begin 
with a period. THINK Pascal automatically inserts the null for you in desk 
accessories and adds the period to device driver names if you’ve left it out. 

Type Desk accessories and device drivers are resources of type DRVR. You can 

change the type if you have some reason for doing so. 

ID This field is the number of the DRVR resource. Desk accessories default to 12. 

The Font/DA Mover renumbers it (and its owned resources) for you if there is an 
ID conflict with an installed desk accessory, so you shouldn’t have to change the 
number. If the Multi-Segment option is on, the ID must be between 0 and 63. 

Attributes This pop-up menu let you set the attributes for the DRVR resource. To learn 

about resource attributes see Inside Macintosh I, Chapter 5, “The Resource 
Manager.” 

Multi-Segment When this option is checked, your desk accessory can have up to 31 segments. 

If your desk accessory uses Object Pascal, this option must be on. 


240 




THINK Pascal Menus 


16 


Flags This pop-up menu lets you set the drvrFlags field of the driver’s header. 

These flags let the operating system know what driver calls your driver responds 
to. The default for desk accessories is $ 0 4 0 0. For device drivers the default is 
$4F00. For more information about driver headers, see Inside Macintosh II, 
Chapter 6, “The Device Manager.” 

Delay This field lets you set the drvrDelay flag of the driver’s header. The value in 

this field lets the operating system know how often it needs to call your driver 
for some periodic action. For this field to make sense, you must have the 
dNeedTime bit set in the drvr Flags field. 

Mask This pop-up menu lets you set the drvrEMask field of the driver’s header. The 

mask lets the system know which events your desk accessory responds to. (This 
field isn’t used in device drivers.) 

CODE RESOURCE 
The Code Resource dialog lets 
you specify the type, name, id, 
and attributes of your code 
resource. 


Name This field lets you name your code resource. For most code resources, the name 

is optional. 

Type This field lets you specify the type of the code resource. 

ID This field lets you specify the ID of the code resource. 

Attributes This pop-up menu lets you specify the attributes of your code resource. To learn 
about resource attributes see Inside Macintosh I, Chapter 5, “The Resource 
Manager.” 

Multi-Segment When this option is checked, your code resource can have up to 31 segments. If 
your desk accessory uses Object Pascal, this option must be on. If the Multi- 
Segment option is on, the ID must be between 0 and 63. 

Segment Type When the Multi-Segment option is checked, this field lets you you specify the 
resource type of the owned segments. 



241 




THINK Pascal User Manual 


Custom When this option is on, THINK Pascal does not generate the standard resource 

Header header. Instead, the object code for the file that contains main is guaranteed to 

appear first in the resource. See Chapter 12 for details. 

Compile Options... 

This command lets you define compile-time variables for the project, and it lets you specify some 
code generation options. When you choose this command, you’ll see this dialog box: 



Compiler You can define any compile-time variables in this large edit box just as if you 

Variables had used the { $SETC} compiler directive. 

‘USES* If this option is on, you can use these features: 

Extensions 

• Propagated uses. If your unit uses other units, any unit that uses 
your unit also uses those units automatically. 

• Implementation uses. You can put a uses clause in a unit’s 
implementation section. 

For more information, see “The uses clause,” in Chapter 10, “Units and 
Libraries.” 

68020/68030 When this option is on, THINK Pascal generates code for the MC68020 and 
MC68030 CPUs found in some Macintosh models and accelerator boards. 

Note: THINK Pascal doesn’t check to see whether the machine you’re writing 
your program on or whether the machine your application runs on has an 
MC68881 or MC68882 floating point unit. Use the Gestalt Manager, described in 
Inside Macintosh VI, Chapter 3, “Compatibility Guidelines,” or SysEnvirons, 


242 





THINK Pascal Menus 


16 


described in Inside Macintosh V, Chapter 1, “Compatibility Guidelines.” If you 
want to check for the machine’s capabilities, you’ll need to turn off automatic 
initializations. 

68881/68882 When this option is on, THINK Pascal generates code for the MC68881 and 

MC68882 floating point units for all floating point operations. For more informa¬ 
tion on how you can use this option together with the Elems881 compiler 
variable, see ”68881/882 option” in Chapter 15, “Compiler Directives.” 

Note: THINK Pascal doesn’t check to see whether the machine you’re writing 
your program on or whether the machine your application runs on has an 
MC68881 or MC68882 floating point unit Use the Gestalt Manager, described in 
Inside Macintosh VI, Chapter 3, “Compatibility Guidelines,” or SysEnvirons, 
described in Inside Macintosh V, Chapter 1, “Compatibility Guidelines.” If you 
want to check for the machine’s capabilities, you’ll need to turn off automatic 
initializations. 

Long Names When the Names option is on, THINK Pascal embeds subroutine names into the 
code right after the end of the procedure or function. Debuggers such as 
LightsBug, Macsbug, and TMON use these names. If the “Long Names” option is 
on, names can be any length. If it’s off, THINK Pascal stores only the first eight 
characters of the name. For more information on the Names option, see Chapter 
15, “Compiler Directives.” 

Large Sets THINK Pascal lets you specify whether sets of integer include all integers 
(-32768 . . 32767) or just the range 0 . . 255. Most of the time, you’ll use the 
smaller set range. The larger set range takes up considerably more space in your 
program and takes much longer to access than the smaller range. Sets of the 
range 0 . . 255 can take up at most 32 bytes. Sets of the range -32768 . . 32767 
can take u p to 8192 bytes. 

Profile When the Profile option, THINK Pascal profiles your code. It collects statistics 

about your program, including the time spent in each routine. For more 
information, see Chapter 19, “The Profiler.” 

For more information on this command, see “Using the Compile Options Command” in Chapter 15. 


243 




THINK Pascal User Manual 


View Options... 

This command lets you customize what appears in the project window. When you choose this 
command, you’ll see this dialog box: 


Project Uleui Settings 


Options File (by build order) 

Size 

(ME1 V[0 MemHecks 

32767 

EMSEl Extr.rn.lg v-l-d 

10 


^filename □ unit name 
^options □ uolume name 
H code size □ date file saued 

File Information 


| Geneua | | 9 | 


[ OK [ Cancel ] 


Options - Bowed indicates enabled 
D - Debug. Rllouis stepping, stopping, stack checking, Observing. 
N - Names. Insert Macsbug names into the code. 

U - Integer arithmetic overflow checking. 

R - Range checking. 


The two pop-up menus let you choose the font THINK Pascal uses to display the file names in the 
project window. The check boxes let you choose the information that appears for each file. The 
box at the top of the dialog box shows you what the project window would look like with the 
current settings. 


Option 

filename 
options 
code size 
unit name 
volume name 
date file saved 


Meaning 

Displays the name of the file. 

Displays the compiler options. 

Displays the size of the compiled code. 

Displays the unit name if the file has been compiled. 
Displays the volume or folder the file is in. 

Displays the last date and time you saved the file. 


The order that you click the check boxes determines the order of the display. 


244 










THINK Pascal Menus 


16 


Get Info... 

This command shows how much code and data each file in your project produces. Choosing the 
command brings up this dialog: 


Runtime .lib 

Interface .lib 

PrintTreps.p 

Script p 

Objlntf.p 

o 

EmbedDefProo .p 


PrintDialogs .p 


ODIntf.p 


ODMDefs.p 


0DMenu.p 


ODTDrawVindov.p 


ODTList.p 


ODTPkVindow.p 

is 

ODTShape .p 

is: 

ODTWindowp 

a 


Project Total*: 

Coda: 59846 bytes 
Global Data: 2250 bytes 
Jump Table: 6640 bytes 

DialogUtils p: 

Coda: 4588 bytas 
Global Data: 10 bytas 
Jump Tabla: 272 bytas 



The list on the left contains all the files in your project. To examine a file, click on it. To examine 
several files in a range, hold down the Shift key and select the range. To examine several scattered 
files, hold down the Command key and click on each file. 

The right side displays the amount of code and data. On top, the “Project Totals” displays total 
amount of code and data in your project. Underneath is the amount of code and data that the 
selected file (or files) contributes to the total. 


This table explains what the dialog displays: 


Tide 

Code 

Global Data 
Jump Table 


Meaning 

The amount of object code. This is same number in the Size column of 
the project window. 

The amount of global data. 

The size of the jump table, which contains the addresses of functions 
and procedures in your application. 


245 







THINK Pascal User Manual 


The Run Menu 

The commands and options in the Run menu let you compile and run your program. When you 
hold down the Option key, this menu has automatic versions for some commands. When you hold 
down the Shift key, this menu lets you compile individual files. 


Run 


Check SyntaH 96K 


Build 96B 

Check Link 
Reset 


Go 96G 

Step Ouer MJ 

Step Into 961 

Step Out 96U 


Ruto Saue 
✓Confirm Saues 
Don't Saue 


Run Options... 


The Run menu 


Run 


Check Syntau 

96K 

Build 

96 B 

Check Link 


Reset 


Go-Go 

96G 

Step Ouer 

96J 

Step-Step 

961 

Step Out 

96U 


Ruto Saue 
✓Confirm Saues 
Don't Saue 


Run Options... 


The Option Run menu 


Run 


Compile 

Build 

Check Link 
Reset 

96K 

96B 

Go 

96G 

Step Ouer 

96J 

Step Into 

961 

Step Out 

96U 

Ruto-Saue 


✓ Confirm Saues 


Don't Saue 


Run Options... 


The Shift Run menu 


Check Syntax 
Compile 

The Check Syntax command checks the Pascal syntax of the current edit window or of the Instant 
window. 


The Compile command compiles the current edit window and updates the project document. To 
see the Compile command, hold down the Shift key as you select the Run menu. 

Build 

This command compiles all the files that have changed or that use a unit whose interface section 
has changed. 

The execution commands — Go, Step Into, Step Over, Go-Go, and Step-Step — do an 
implicit Build before executing the program. 

Check Link 

This command links all the files in the project. If THINK Pascal finds an undefined symbol or a 
symbol defined more than once, it reports an error. 









THINK Pascal Menus 


16 


The execution commands — Go, Step Into, Step Over, Go-Go, and Step-Step — do an implicit 
Check link before executing the program. If there are files that need to be recompiled, THINK 
Pascal asks you if you want to recompile them. 

Reset 

This command resets a paused program. The next execution command — Go, Step Into, Step 
Over, Go-Go, and Step-Step — starts the program from the beginning. 

Go 

Go-Go 

The Go command runs your program, pausing at the Stop Signs you placed in your code. 

You can think of Go-Go as the automatic version of Go, choosing Go again and again. To see the 
Go-Go command, hold down the Option key and choose the Run menu. 

The Go-Go command runs your program without stopping. It pauses at Stop Signs to move the 
execution finger and update the Observe and LightsBug windows. 

Both commands build the project first, if necessary. 

If you hold down the Shift key when you choose either command, THINK Pascal lets you examine 
your compiled code with a low-level debugger, such as TMON or Macsbug. It breaks into the low- 
level debugger at an RTS instruction just before the actual code for the statement. 

Step Over 

This command executes the next statement in your program. It then moves the execution finger, 
and updates the Observe and LightsBug windows. If the statement has a function or procedure call, 
this command executes the routine without moving the execution finger into it. 

This command builds the project first, if necessary. 

If you hold down the Shift key when you choose this command, THINK Pascal lets you examine 
your compiled code with a low-level debugger, such as TMON or Macsbug. It breaks into the low- 
level debugger at an RTS instruction just before the actual code for the statement. 

Step Into 
Step-Step 

The Step Into command executes the next statement in your program. It then moves the execution 
finger and updates the Observe and LightsBug windows. If the statement has a function or 
procedure call, this command moves the execution finger to the first line of the routine. 

You can think of Step-Step as the automatic version of Step Into, choosing Step Into again and 
again. To see the Step-Step command, hold down the Option key and choose the Run menu. 

The Step-Step command executes your program statement by statement. It pauses after each 
statement to move the execution finger and update the Observe and LightsBug windows. If a 


247 



THINK Pascal User Manual 


statement has a function or procedure call, this command moves the execution finger into the 
routine. 

Both commands build the project first, if necessary. 

If you hold down the Shift key when you choose either command, THINK Pascal lets you examine 
your compiled code with a low-level debugger, such as TMON or Macsbug. It breaks into the low- 
level debugger at an RTS instruction just before the actual code for the statement. 

Step Out 

This command continues executing until it returns from the current routine. You’ll find this 
command especially useful if you accidentally step into a routine with the Step Into command. 

This command builds the project first, if necessary. 

If you hold down the Shift key when you choose this command, THINK Pascal lets you examine 
your compiled code with a low-level debugger, such as TMON or Macsbug. It breaks into the low- 
level debugger at an RTS instruction just before the actual code for the statement. 

Auto-Save 
Confirm Saves 
Don’t Save 

These three options determine what THINK Pascal does with files that you’ve changed but haven’t 
saved when you choose one of the execution commands in the Run menu. 

The three options are mutually exclusive. You can choose only one. 

Auto-Save When this options is checked, THINK Pascal automatically saves your files 

before running your project. 

If you hold down the Shift key and then choose Auto-Save, THINK Pascal saves 
all your unsaved files without changing the current option. 

Confirm Saves When this option is checked, THINK Pascal asks if you want to save your 
unsaved files before running your project. 

If you hold down the Shift key and then choose Confirm Saves, THINK Pascal 
asks you if you want to save each of your unsaved files. 

Don’t Save When this options is checked, THINK Pascal doesn’t do anything with your 
unsaved files before running your project. 


248 



THINK Pascal Menus 


16 


Run Options... 

This command lets you set up certain run-time environment settings. When you choose this 
command you’ll see this dialog box: 


Run-time Enuironment Settings 


Resources 


□ Use resource file: 

for resources used by the project. 


Tent 

LUindouj 


Tent Window saues |5000 [ characters 
□ Echo to the printer 


□ Echo to the file: 


H«llo world, x * 811.75. 


Monaco 

izi 


Memory 


Stack size: |[|3|[] kilobytes 
Zone size: | 128 | kilobytes 


» "* i 

f Cancel } 


Resources When you check this box, THINK Pascal lets you choose the resource file your 
program uses. To learn more about using resource files with your THINK Pascal 
projects, see Chapter 8 and Chapter 12. 

NOTE: THE RESOURCE FILE MUST BE IN THE SAME FOLDER AS THE PROJECT 
AND CANNOT BE AN ALIAS. 

Text Window This part of the dialog lets you configure the THINK Pascal Text window. 

THINK Pascal uses the Text window for all standard output, for instance write, 
writeln, read, etc.. 

You can specify how many characters THINK Pascal saves in the Text window. 
The default is 5000 characters. If you write more than that to the text window, 
the earlier text disappears. 

The Echo to printer and Echo to a file check boxes let you send the standard 
output to the printer or to a file as well as to the Text window. 

The pop-up menus let you choose the font and size of text in the Text window. 


249 






THINK Pascal User Manual 


Memory These options let you choose how much memory THINK Pascal allocates for 

your project’s stack and heap zone. If your program is running out of memory, 
try making the zone size bigger. If your program allocates a lot of local variables, 
or if it uses very deep recursion, you might want to make the stack size bigger. 

In most cases, 16K is more than enough. 

Note; When you build your application, THINK Pascal uses the 
stack size value you specify, unless you turn off initialization 
with the { $1 -} directive. The zone size value applies only 
while you’re running in the THINK Pascal environment. 

The Debug Menu 

The Debug menu commands and options let you control THINK Pascal’s debugging features. 

When you hold down the Option key, you can remove all the Stop Signs in your project at once. 

When you hold down the Shift key, you can create new LightsBug windows and use your low-level 

debugger. 


Debug 


LightsBug XL 

Instant 

Obserue 


Show Finger 
Pull Stops 


Ruto-Show Finger 
Stops In 

Break at R-Traps 


Use Second Screen 
Quietly Ruto-Reset 


Monitor XM 


The Debug menu 


Debug 


LightsBug XL 

Instant 

Obserue 


Show Finger 
Pull Rll Stops 

Ruto-Show Finger 
Stops In 

Break at R-Traps 

Use Second Screen 
Quietly Ruto-Reset 


Monitor XM 


The Option Debug menu 


Debug 


New LightsBug XL 

Instant 

Obserue 


Show Finger 
Pull Stops 


Ruto-Show Finger 
Stops In 

Break at R-Traps 


Use Second Screen 
Quietly Ruto-Reset 


Use Monitor XM 


The Shift Debug menu 


LightsBug 
New LightsBug 

The LightsBug command opens a LightsBug debugging window. You can open up to four 
LightsBug windows. Choosing the LightsBug command (or its Command key equivalent) when 
LightsBug windows are open cycles through all the open LightsBug windows. 


The New LightsBug command creates a new LightsBug window. To see the New LightsBug 
command, how down the Shift key as you select the Debug menu. 


250 

















THINK Pascal Menus 


16 


Instant 

This command opens the Instant window, which is used for executing statements when your 
program is paused. 

Observe 

This command opens the Observe window, which displays the values of expressions during 
program execution. 

Show Finger 

This command makes the window that contains the execution finger the active window. If neces¬ 
sary, it scrolls the window so you can see the execution finger. If the window that would contain 
the execution finger is not open, the project window becomes the active window, and the 
execution finger points at the file name. 

Pull Stops 
Pull All Stops 

The Pull Stops command removes all Stop Signs from the current edit window. The Pull All Stops 
command removes all Stop Signs from all the files in the project. 

Auto-Show Finger 

You can think of this command as an automatic version of Show Finger. When this option is 
checked, and THINK Pascal is executing a Step Into, Step Over, Go-Go, or Step-Step command, 
the window that contains the execution finger becomes the active window. If the file that would 
contain the execution finger isn’t opened, the execution finger points to the file name in the project 
window. 

Since this command changes the active window, it’s a good idea to turn this option off when you’re 
debugging the code that handles activate and update events in your application. 

Stops In 

This option lets you add Stops to your Pascal code. To add a Stop to your program, move the cur¬ 
sor to the left column of your program. The cursor changes to a Stop sign. When you click the 
mouse, a Stop sign appears to the left of the line of code. 

To remove a Stop Sign, click on it. 

When you choose the Go or Step-Step command, THINK Pascal stops execution right before the 
Stop sign. 

Break at A-Traps 

When this option is on, THINK Pascal stops execution before calling a Macintosh Toolbox routine. 
Use this option to make sure that you’re passing the proper values to Toolbox routines. 

Use Second Screen 

If this option is on and if you have two screens, THINK Pascal places the Instant, Observe, and 
LightsBug windows on your second screen. 


251 



THINK Pascal User Manual 


Quietly Auto-Reset 

If you’re running a program under THINK Pascal and you try to change your source files or the 
project, THINK Pascal displays a warning and asks if you want to cancel your change or reset the 
program. If this option is on, THINK Pascal won’t warn you and automatically resets your program. 

Monitor 
Use Monitor 

The Monitor command drops you into the low-level debugger (Macsbug or TMON) if it’s installed. 

The Use Monitor command lets you choose which debugger you use when THINK Pascal comes 
to an exception. If the Use Monitor option is on, you use the low-level debugger, like TMON or 
Macsbug. If the Use Monitor option is off, you use LightsBug. A diamond appears next the the 
Use Monitor and Monitor commands when this option is on. To see the Use Monitor command, 
hold down the Shift key as you select the Debug menu. 


The Windows Menu 

The commands in the Windows menu help you work with the THINK Pascal windows. 


Windows 


MyProject.rf 

980 

arrange... 
v'Ruto-Reopen 
'/’Saue Positions 

Class Browser 

sea 

Tent 


Drawing 


Filel.p 

981 

File2.p 

982 

File3.p 

983 


VA 


The Windows menu 
Project name 

This command makes the project window the active window. 

Arrange... 

This command arranges the editing windows. The Arrange... dialog box lets you choose one of 
four ways. To choose an option, either click on its icon and click OK or just double-click on its 
icon. If you change your mind, click Cancel. 


252 







THINK Pascal Menus 


16 


These are the four options: 



□□ 


□□ 

□□ ( QIC ) 



Overlapping. The first window is the about the length 
of the screen. The top of each subsequent window is 
placed just below the previous window’s title bar. After 
five windows, the cycle starts over. 


□ 

co 

□□ 

l »•< ) 

□□ 

w 

[ Cancel ] 


Tiled. All windows are completely visible. The screen 
is split into as many sections (approximately equal in 
size) as there are editing windows. Each window is 
placed in a section. 




CO 

ns ( ok i 

0 

□□ 


f—’——) [ Cancel ] 


Side-by-side horizontally. One window is in the left 
half of the screen; the rest are in the right. Only two 
editing windows are visible. 



Side-by-side vertically. One window is in the top 
half of the screen; the rest are in the bottom. Only two 
windows are visible 


Auto-Reopen 

If checked, opens a project’s windows automatically whenever a project is opened. (This affects all 
windows: the editing windows, and the project, Observe, Instant, and LightsBug windows.) 

Save Positions 

If checked, saves the positions of the windows when the project is closed. Next time the project is 
opened, the windows open in the same place. (This affects all windows: the project window, the 
editing windows, and the Observe, Instant, and LightsBug windows.) 

Class Browser 

This displays the Class Browser window, which shows the hierarchy of your classes and helps you 
explore it. For more information, see the Object-Oriented Programming Manual, Chapter 6. 


253 






THINK Pascal User Manual 


Text 

This command opens the Text window which THINK Pascal uses for standard output like write 
and writeln. 

Drawing 

This command opens the Drawing window which THINK Pascal uses as the default drawing port 
for your program. 

File Windows 

Use these commands to activate one of the currently open editing windows. A diamond appears 
next to files which have been changed but haven’t been saved. If you hid a window by clicking in 
its close box, choosing its name in this menu makes it visible. 


254 



Language Reference 

17 


Introduction 

This chapter describes the Pascal language implemented by THINK Pascal. THINK Pascal is 
intended to be compatible with Macintosh Pascal, Apple’s Macintosh Programmer’s Workshop 
Pascal, and American National Standard Pascal. Naturally, it’s impossible to be completely 
compatible with all three implementations. Appendixes B and C detail the differences between 
THINK Pascal and other implementations of Pascal. 

Related Documents 

Pascal User Manual and Report, Third Edition (ISO Pascal Standard) by Jensen and Wirth, revised 
by Mickel and Miner, Springer-Verlag, New York, 1985. 

American National Standard Pascal Computer Programming Language, ANSI/ IEEE770X3.97- 
1983, IEEE/Wiley-Interscience, 1983. 

Object Pascal Reportby Larry Tesler. Apple Technical Report No. 1. Apple Computer 1985. 

Inside Macintosh I-VI, Addison Wesley, 1985-1991. 


Apple Numerics Manual, Second Edition (Addison-Wesley) 

Definitions 

This chapter uses these definitions for the terms error, undefined, and unspecified: 

Error Any misuse of the Pascal language described in this chapter. Most of these 

errors are detected at compile time or at run time. Other errors are not de¬ 
tected; these are listed in Appendix B. The behavior of a program that con¬ 
tains undetected errors is unspecified. 

Undefined A value of a variable or of a function that is not meaningful. It is an error to 
use an undefined value. 


Unspecified When a situation arises in the execution of a program where several courses 
of action are possible, the specific course chosen is said to be unspecified. 
This means that the program should not depend on any specific course be¬ 
ing chosen, as the result may be unpredictable. This leaves the implementa¬ 
tion free to choose the course that is most convenient at the time. 



THINK Pascal User Manual 


Notation and syntax diagrams 

All numbers in this manual are in decimal, except where hexadecimal notation is specifically 
indicated. 

In this section, Pascal text is in typewriter text, and Pascal reserved words are in bold 
typewriter text. For example: 

sqr(n div 16 ) 

Sometimes the same word appears both in plain text and in typewriter text. For example, “The 
declaration of a Pascal procedure begins with the word procedure.” 

Technical terms appear in bold face when they’re introduced. 

Pascal syntax is specified with diagrams. For example, this diagram gives the syntax for an 
identifier: 



Start at the left and follow the arrows through the diagram. There are several paths you can take. 
Every path begins at the left and ends at the arrow-head on the right, and represents a valid way to 
construct an identifier. The boxes represent the elements that can be used to construct an identifier. 
The diagram represents the following rules: 

• An identifier must begin with a letter, since the first arrow goes directly to a box named “letter”. 

• An identifier might consist of nothing but a single letter, since there is a path from this box to the 
arrow-head on the right, without going through any more boxes. 

• The initial letter may be followed by another letter, a digit, or an underscore, since there are 
branches from the initial letter box to these boxes. 

• The initial letter may be followed by any number of letters, digits, or underscores, since there is 
a path that leads from these boxes back to them again. 

A word contained in a rectangular box may be a name for an atomic element like “letter” or “digit,” 
or it may be a name for some other syntactic construction that is specified by another diagram. The 
name in the rectangular box is to be replaced by an actual instance of the atom or construction that 
it represents, e.g. 3 for “digit” or counter for “variable-reference”. 


256 







Language Reference 17 


Pascal symbols, such as reserved words, operators, and punctuation, are in bold face and are en¬ 
closed in circles or ovals, as in the following diagram for the construction of a compound- 
statement: 


compound-statement 

-^ begin 


statement 


o 


+ Q end} 


Text in a circle or oval represents itself, and is written as shown (except that case of letters is not 
significant). In the diagram above, the semicolon and the words begin and end are symbols. The 
word “statement” refers to a construction that has its own syntax diagram. 

So this diagram means that a compound-statement consists of the reserved word begin, followed 
by any number of statements separated by semicolons, followed by the reserved word end. 


1.0 Tokens and Constants 

Tokens are the smallest meaningful units of text in a Pascal program. Structurally, they correspond 
to the words and punctuation of an English sentence. The tokens of Pascal are classified into 

special symbols, identifiers, numbers, labels, and character-strings. 

The text of a Pascal program consists of tokens and separators, where a separator is either a 
blank or a comment. Two adjacent tokens must be separated by one or more separators if each 
token is an identifier, number, or word-symbol. 

Separators cannot be embedded within tokens except in character-strings. 

1.1 Character set and special symbols 

THINK Pascal uses the Macintosh character set. Letters, digits, hex-digits, and blanks are subsets of 
the character set: 

• Letters are the characters A through Z and a through z. 

• Digits are the Arabic numerals 0 through 9; the hex-digits are the Arabic numerals 0 through 
9, the letters A through F, and the letters a through f . 

• The blanks are the space character and the end-of-line character (CR). 

Special-symbols and word-symbols (also called reserved words) are tokens that have one or 
more fixed meanings. The following single characters are special-symbols: 

+ -*/ = <>[].,() 


257 




THINK Pascal User Manual 


The following character-pairs are special-symbols: 

<> <= >= := ..(**) (. .) 

Note: The special symbol “ (. ” is an alternate representation for the special sym¬ 
bol “ [ ”. Both actually denote the same special symbol. If you type “ (. ” in a 
THINK Pascal program, it will always be displayed as “ [ ”. The same is true for 
“.) ” and “ ] 

The following are the word-symbols: 


and 

function 

object 

to 

array 

goto 

of 

type 

begin 

if 

or 

unit 

case 

implementation 

otherwise 

univ 

const 

in 

packed 

until 

div 

inherited 

procedure 

uses 

do 

inline 

program 

var 

downto 

interface 

record 

while 

else 

label 

repeat 

with 

end 

mod 

set 


file 

nil 

string 


for 

not 

then 



Upper and lower case letters are equivalent in word-symbols. 

1.2 Identifiers 

Identifiers serve to denote constants, types, variables, procedures, functions, programs, and fields 
in records. Identifiers can be up to 255 characters long. All characters are significant. Upper and 
lower case letters are equivalent in identifiers. No identifier can have the same spelling as a word- 
symbol. 



Examples of identifiers: 

X Rome gcd SUM get_byte 


258 



Language Reference 17 


1.3 Directives 

Directives are identifiers that have special meanings in specific contexts. They can be used as iden¬ 
tifiers in all other contexts. For example, the word forward is interpreted as a directive if it occurs 
immediately after a procedure-heading or function-heading, but in any other position it is 
interpreted as an identifier. 

THINK Pascal recognizes these three directives: 

external 

forward 

override 

Note: Don’t confuse these directives with compiler directives. 

1.4 Numbers 

The usual decimal notation is used to represent numbers that are constants of the data types 
integer, longint, real, double, extended, and computational (see § 3.1). A hexadeci¬ 
mal integer constant uses the $ character as a prefix (1-4 hex-digits for integer, 5-8 hex-digits for 
longint). 



unsigned-real 



259 










THINK Pascal User Manual 



The letter E or e preceding the scale in an unsigned-real means “times ten to the power of.” 
Examples of numbers: 

1 +100 -0.1 5E-3 87.35e+8 $A05D 

Note that 5E-3 means 5x10'^, and 87.35e+8 means 87.35x10®. 

1.5 Labels 

A label is a digit-sequence whose value is in the range 0 through 9999. Leading zeros in a label 
are insignificant. The labels 1 and 0001 are equivalent. 

1.6 Character-Strings 

A character-string is a sequence of zero or more printing characters on the same line in a pro¬ 
gram and enclosed by single quotes. The maximum number of characters that can be in a charac¬ 
ter-string is 255. A character-string with nothing between the apostrophes is a null-string value 
(see §3.3). Two adjacent apostrophes in a character-string denotes a single apostrophe character. 


character-string 



260 












Language Reference 17 


A character-string represents a value of a string-type. As a string-type, a character-string is compat¬ 
ible not only with other string-types, but also char-types (see §3.1.1.1) and packed-string-types 
(§ 3 . 2 . 1 ). 

All string-type values have a length attribute. In the case of a character-string, the length is fixed; it 
is equal to the number of characters in the string as enclosed within apostrophes. Two adjacent 
apostrophes within a character-string count as a single apostrophe and thus count as a single 
character in the string’s length. 

Examples of character-strings: 

'Pascal' 'THIS IS A STRING' 'Don''t worry!' 

i . * i * i i it 

1.7 Constant-Declarations 

A constant-declaration declares an identifier to denote a constant within the block that contains 
the declaration. A constant-identifier may not be included in its own declaration. 



A constant-identifier following a sign must denote a value of type set, character-string, integer, 
longint, boolean, char, real, double, computational or extended (see §3.1). 

A constant expression must evaluate to a set, character-string, integer, longint, boolean or 
char. You can use the following operators and standard functions in a constant expression: 


* (multiplication) 

+ (addition) 

- (subtraction) 

* (set intersection) 

+ (set union) 

- (set difference) 

div 

mod 

abs 

chr 

ord 

sizeof 

sqr 




261 









THINK Pascal User Manual 


1.8 Comments 

The constructs: 

{ any text not containing right-brace } 

(* any text not containing star-right-paren *) 
are called comments. 

You can use a comment anywhere you can use a blank. THINK Pascal moves any comments em¬ 
bedded in a line of code to the end of the line. Comments that appear alone in a line are left alone. 
If you try to extend a comment over more than one line, THINK Pascal adds a } or *) at the end of 
one line and a { or (* at the beginning of the next. 

You can’t nest comments within other comments. A } or a *) always terminates a comment. 

1.9 Compiler Options 

A compiler option is a comment that contains the $ character immediately following the initial 
comment delimiter; for example, { $ or (* $. The $ character is followed immediately by the 
mnemonic of the compiler option, (see Chapter 15 for available options). A compiler option is 
always on a line by itself. 


2.0 Blocks, Scopes, and Activations 

2.1 Definition of a Block 

A block consists of a declaration-part and a statement-part. Every block is part of a procedure- 
declaration, a function-declaration, or a program. All identifiers and labels that are declared in the 
declaration-part of a block are local to that block. 


block 


declaration-part 


statement-part 


declaration-part 


label-declaration-part 


constant-declaration-part 


type-declaration-part 




variable-declaration-part 


procedure-and-function-declaration-part 


262 






Language Reference 17 


A label-declaration-part declares labels (see §1.5) that mark statements in the corresponding 
statement-part. Each label must mark exactly one statement in the statement-part. 


1abel-declaration-part 



label 


digit-sequence 


A constant-declaration-part contains constant-declarations (see §1.7) local to the block. 


constant-declaration-part 



A type-declaration-part contains type-declarations (see §3) local to the block. 


ty pe-declaration -part 



A variable-declaration-part contains variable-declarations (see §4) local to the block. 


variable-declaration -part 



A procedure-and-function-declaration-part contains procedure-, function-, and method- 
declarations (see §7) local to the block. 


procedure-and-function-declaration-part 













THINK Pascal User Manual 


Note: A method declaration can only be declared in the declaration-part of a pro¬ 
gram or in the implementation part of a unit, not in the declaration-part of a 
procedure or function. 

The statement-part specifies the statements or algorithmic actions (see §6) to be executed upon an 
activation (see §2.3) of the block. 


statement -part 


< 


compound-statement 



2.2 Rules of Scope 

This section describes the rules that THINK Pascal uses to determine what identifiers are visible to a 
particular block. 

2.2.1 Scope of a Declaration 

The appearance of an identifier or label in a declaration declares the identifier or label. All other 
applied occurrences of the identifier or label must be within the scope of this declaration. 

The scope of a declaration is the block that contains the declaration, and all blocks enclosed by that 
block except as explained in §2.2.2 and §2.2.4 below. (See also §8.3 for scope rules for Units.) 

2.2.2 Redeclaration in an Enclosed Block 

Suppose that outer is a block, and that inner is another block declared within outer. If an 
identifier declared in block outer has the same spelling as an identifier declared in block inner, 
then block inner and all blocks enclosed by inner are excluded from the scope of the 
declaration in block outer. 

2.2.3 Position of Declaration within Its Block 

The declaration of an identifier or label must precede all applied occurrences of that identifier or 
label in the program text. In other words, identifiers and labels cannot be used until they are 
declared. 

There are two exceptions to this rule. In a type-declaration-part, the base-type of a pointer-type 
(see §3.4) can be an identifier that has not yet been declared. In this case, the identifier must be 
declared somewhere in the same type-declaration-part as the pointer-type. The base-type of an 
object-type (§3.2.5) can also be an identifier that has not been declared, and the identifier must be 
declared somewhere in the same type-declaration-part as the object type. 

2.2.4 Redeclaration within a Block 

An identifier or label cannot be declared more than once within a block, unless it is declared within 
a contained block, or it is in a record’s field-list. 

A field-identifier (see §§3.2.2 and 4.3.2) is declared within a record-type. It is meaningful only in 
combination with a reference to a variable of that record-type. Therefore, a field-identifier can be 
declared within the same block as another identifier with the same spelling, as long as it has not 
been declared previously in the same field-list. An identifier that has been declared can be used 
again as a field-identifier in the same block. 


264 





Language Reference 


17 


2.2.5 Identifiers of Standard Objects 

THINK Pascal provides a set of standard (predeclared) constants, types, procedures, and functions 
that behave as if they were declared in a block that contains the entire program. In addition, there 
are two standard file variables, input and output, that (if used) are “declared” in the program 
block itself (see §9.4). 

2.2.6 Scope of Interface Identifiers 

Each interface-part or program with a uses-clause (see §8.4) is supplied with the identifiers associ¬ 
ated with the unit given in the uses-clause. This means that these identifiers behave as though they 
were declared directly in each interface-part or program with the uses-clause. 

2.2.7 Scope of fields 

In the implementation of a method of an object-type (§3.2.5) all of the identifiers and components 
of the type and its ancestors are meaningful. The behavior is as if the statement-list of the block 
were wrapped in with self do begin ... end. 

2.3 Activations 

The execution of a block is referred to as an activation of the block. At any given time, a block 
normally has either no activations (if it is not currently being executed) or one activation (if it is 
begin executed). It is, however, possible for a block to have multiple activations if it is recursive or 
if it is mutually recursive with one or more other procedures or functions. A typical example of a 
recursive function is: 

function factorial (n: integer): integer; 

begin 

if n<=l then 

factorial := 1 

else 

factorial := n * factorial(n-1) 

end; 

Thus, the execution of factorial (5) would lead to 5 activations of factorial as follows: 

factorial (5) = 5 * factorial(4) 

=5*4* factorial(3) 

= 5 * 4 *3 * factorial(2) 

= 5*4*3*2* factorial (1) 

= 5*4*3*2*1 

Factorial calls itself repeatedly, creating new activations, until the parameter n is less than or 
equal to 1. The last activation then unwinds itself by passing back a result and terminating the acti¬ 
vation. The next to last activation then performs the multiplication with the result, passes back its 
result, and terminates its activation, and so on. 

Every activation has, in effect, its own copy of every parameter and variable declared local to the 
block being activated. Thus, each activation of factorial has its own copy of its parameter, 
which is named n in all activations. Because each activation has its own copy of all locally declared 

265 



THINK Pascal User Manual 


entities, it does not disturb the local entities of any previous activation. §7.3*3 gives a very detailed 
example of this. 

The activation of the program-block also creates the variables local to each used unit’s interface- 
part and implementation-part (see §8.3). This means that there is only one copy of each unit’s local 
variables and that they exist as long as the program is executing. 

Notes The value of a variable declared within a particular block is undefined for 
each new activation of the block. Likewise, the value of every component of a 
structured-type variable (see §3.2) is initially undefined for each new activation. 

The value of a structured-type variable remains undefined until it has no 
components whose values are undefined. 

3.0 Types 

A type is used in declaring variables and in declaring other types. The type of a variable deter¬ 
mines the set of values the variable can assume and the operations that can be performed upon it. 
A type-declaration associates an identifier with a type. 


type -declarat ion 



The occurrence of an identifier on the left-hand side of a type-declaration declares it as a type- 
identifier for the block in which the type-declaration occurs. A type-identifier may not be included 
in its own declaration, except for pointer-types (see §2.2.3 and §3.4). 

To help clarify the syntax description with some semantic hints, the following terms distinguish 
identifiers according to the type they denote. Syntactically, all of them simply mean an identifier: 

• simple-type-identifier 

• structured-type-identifier 

• pointer-type-identifier 

• ordinal-type-identifier 

• integer-type-identifier 


2 66 









Language Reference 


17 


• real-type-identifier 

• string-type-identifier 

In other words, a simple-type-identifier is any identifier that is declared to denote a simple-type, a 
structured-type-identifier is any identifier that is declared to denote a structured-type, and so forth. 
A simple-type-identifier can be the identifier of a standard simple-type such as integer, 
boolean, etc. 

3.1 Simple-Types 

All the simple-types define ordered sets of values. 



An integer-type-identifier is one of the standard identifiers integer or longlnt Constant integer- 

type values can be denoted as described in §§1.4 and 1.7. 

A real-type-identifier is one of the standard identifiers real, double, extended, or 

computational. Constant real-type values can be denoted as described in §§1.4 and 1.7. 

3.1.1 Ordinal-Types 

Ordinal-types are a subset of the simple-types that have the following special characteristics: 

• The possible values of an ordinal-type are an ordered set and every value has an ordlnality, 
which is an integral value. Except for integer-types, the first value of every ordinal-type has or- 
dinality 0, the next has ordinality 1, etc. For integer-types, the ordinality of a value is the value it¬ 
self. Every value of an ordinal-type except the first has a predecessor based on the ordering of 
the type, and every value of an ordinal-type except the last has a successor based on the 
ordering of the type. 

• The standard function ord (see §10.4.1) can be applied to any value of an ordinal-type, and it 
returns the ordinality of the value. 

267 









THINK Pascal User Manual 


• The standard function pred (see §10.4.4) can be applied to any value of an ordinal-type, and it 
returns the predecessor of the value. 

• The standard function succ (see §10.4.3) can be applied to any value of an ordinal-type, and it 
returns the successor of the value. 

The application of pred to the first value of an ordinal-type is an error. Likewise, the application of 
succ to the last value of an ordinal-type is an error. 

All simple-types except the real-types are ordinal-types. 

There are four standard ordinal-types denoted by the standard identifiers: 

integer 

longint 

char 

boolean 

Note that in addition to the standard ordinal-types, the enumerated-types and subrange-types are 
ordinal-types. 

3.1.1.1 Standard Ordinal-Types 

Integer The integer-type integer has a set of values that are a subset of the whole 

numbers. The standard integer constant maxint is defined to be i.e. 
32,767. A variable of type integer can have any value in the range 
-maxint-1. .maxint. Values of type integer are l6-bit, signed, 2s- 
complement numbers. 

Longint The integer-type longint is a type that has a set of values that are also a subset 

of the whole numbers, a somewhat larger subset than those of integer. The 
standard longint constant maxlongint is defined to be 2^-1, i.e. 
2,147,483,647. A variable of type longint can have any value in the range 
-maxlongint-1. .maxlongint. Values of type longint are 32-bit, signed, 
2s-complement numbers. 

There are several arithmetic operators that may be used to perform arithmetic with integer-type 
values. All arithmetic with just integer-type integer operands yields results of type integer. 
When one or both operands are of integer-type longint, the result is always of type longint. A 
longint value may always be used where an integer value is required provided that the value 
falls within the range -maxint-1. .maxint. 

Boolean The ordinal-type boolean is an enumerated-type (see §3.1.1.2) defined as: 

type boolean = (false, true); 


268 



Language Reference 


17 


As a consequence of boolean being an enumerated-type, the following relationships hold: 


false 

< 

true 

ord(false) 

= 

0 

ord (true) 

= 

1 

succ(false) 

= 

true 

pred (true) 

= 

false 


Char The ordinal-type char has a set of values that are characters. The ordering of 

the values is defined by the ordering of the Macintosh character set. The func¬ 
tion-call ord (c), where c is a char value, returns the ordinality of c (see 
§10.4.1). 

A character-string of length 1 may be used to denote a constant char value, provided that the 
character is a printable character. Any value of type char may be generated via the standard 
function chr (see §10.4.2). 

The redeclaration of a standard type-identifier does not affect the operand-types, parameter-types, 
or result-types of certain standard operators, procedures, and functions declared to be that standard 
type (see §5.1 and §10). Neither does it affect the type of any literal token (such as a number) 
declared to be of that type (see §1). 

The redeclaration of the standard constant-identifiers maxint or maxlongint has no effect on 
the set of possible values for the integer-types. 

There are several contexts in which an expression is required to be of the standard type boolean 
(see §6). A redeclaration of the standard type-identifier boolean does not alter this requirement. 

However, the redeclaration of the standard enumerated-constant identifiers false and true will 
affect the value of these identifiers. 

3.1.1.2 Enumerated-Types 

An enumerated-type has an ordered set of values defined by listing the identifiers that denote 
these values. The ordering of these values is determined by the sequence in which the identifiers 
are listed. 


enumerated-type 

—►© H 


identifier 


HO- 


identifier-list 



269 





THINK Pascal User Manual 


The occurrence of an identifier within the identifier-list of an enumerated-type declares it as an 
enumerated-constant for the block in which the enumerated- type is declared. The type of this 
constant is the enumerated-type in which it is declared. 

The ordinality of an enumerated-constant is its position in the identifier-list in which it is declared, 
where the ordinality of the first enumerated-constant in the list is always 0. The ordinality of a value 
of an enumerated-type is the ordinality of the enumerated-constant with the same value. 

When the ord function (see §10.4.1) is applied to a value v of an enumerated-type, it returns an 
integer-type value that is the ordinality of v. 

Examples of enumerated-types: 

color = (red, yellow, green, blue) 

suit = (club, diamond, heart, spade) 

maritalStatus = (married, divorced, widowed, single) 

Given these declarations, yellow is an enumerated-constant of type color with ordinality 1, 
spade is an enumerated-constant of type suit with ordinality 3, and so forth. 

3.1.1.3 Subrange-Types 

A subrange-type has a subset of the values of some ordinal-type that lie within a certain range. 
The syntax for a subrange-type is: 


subrange-type 


Both constants in a subrange-type must be of an ordinal-type and both must be of the same ordi¬ 
nal-type. For all subrange-types of the form a. . b, a must be less than or equal to b. The ordinal- 
type of a and b is referred to as the host-type of the subrange-type. The values of a subrange-type 
a. . b are those values of its host-type whose ordinalities lie between the ordinalities of a and b 
inclusive. 

Examples of subrange-types: 

1 . .100 
- 10..+10 
red..green 

A variable of subrange-type possesses all the properties of variables of the host-type, with the re¬ 
striction that its value must always be one of the values in the range defined by the subrange-type. 


270 





Language Reference 


17 


3.1.2 Real-Types 

The real-types have sets of values that are subsets of the real numbers; in particular those subsets 
of the real numbers that may be represented with a floating-point notation using a fixed number of 
digits. In general, a floating-point notation of a value n is comprised of a set of three values m, b, 
and e such that 

m x be * n 

A real-type uses a floating point notation where b is always 2, and where m and e are integral val¬ 
ues that lie in a range that depends on the particular real-type. The range of values that m and e can 
have determine the range and precision of the real-type. 

Note: For detailed information about the representation of real-type values, see 
Apple Numerics Manual, Second Edition (Addison-Wesley). 

Doing arithmetic with real-type values can lead to results that cannot even be approximated with a 
floating-point notation. For instance, the division of one by zero is nominally Other results make 
even less sense, such as dividing zero by zero. There are, in fact, special real-type values to repre¬ 
sent such results. Normally, however, the generation of such a result by a program is an error and 
results in the premature termination of the execution of the program. 

There are four standard real-types: real, double, extended, and computational. No other 
real-types can be defined. 

The approximate range of positive values representable with the real-types real, double, and 
extended as well as their precision are in Table 3-1: 


Table 3-1 The Real-Types 


Real-Type 

Range 

Decimal Digits 

real 

1.5xl0^ 5 to 3.4X10 38 

7-8 

double 

5.0xl0' 324 to 1.7X10 308 

15-16 

extended 

1.9xl0- 4951 to l.lxlO 4932 

19-20 


Any negative value whose absolute value lies within these ranges is representable with these real- 
types. 

All real-type operands are converted to extended before any arithmetic is performed on them, 
and the results of such arithmetic are always of type extended. An extended value may be used 
anywhere a real or double value is required provided that the value falls within the range of 
values for real or double, respectively. 

The real-type computational is a special real-type where e is always zero, i.e. only integral val¬ 
ues may be represented with computational. Values of type computational must lie in the 
(exact) range -2^+1 to 2^-1, which is approximately -9.2xl0 18 to 9.2xl0 18 . 


271 




THINK Pascal User Manual 


All computational operands are converted to extended before any arithmetic is performed on 
them, and the results of such arithmetic are always of type extended. An extended value may 
be used anywhere a computational value is required provided that the value, when rounded to 
an integral value, falls within the range of values for computational. 

The type computational is intended for those applications where precise, fixed-point decimal 
values are required. No explicit decimal point is ever assumed for a computational value, but 
one can be implicitly assumed by the application. For instance, one can define 

type cents = computational; 

and perform calculations on values of type cents that may also be interpreted as calculations on 
dollar values with an implied decimal point to the left of the second to last decimal digit. A special 
form of the standard procedures write and writeln (see §9.4.3.5) may be used to output a 
computational value with a decimal point inserted between any two decimal digits in the value. 

Note: The SANE data types single and comp are equivalent to the Pascal real- 
types real and computational respectively. All of these names are accepted 
by THINK Pascal. 

3.2 Structured Types 

A structured-type is characterized by the kind of structuring it embodies and by the types of the 
components subject to such structuring. The type of a component may itself be structured, in which 
case the resulting structured-type exhibits more than one level of structuring. There is no inherent 
limit on the number of levels to which types can be structured other than the amount of memory 
available. 



272 


The use of the word packed in the declaration of a structured-type indicates that storage organiza¬ 
tion of all values of that type should be compressed to economize storage, even if this causes the 
access of a component of a variable of this type to be less efficient. 










Language Reference 


17 


3.2.1 Array-Types 

An array-type is a linear array (or vector) of components that are all of one type, called the 
component-type of the array. 


array-type 



The type that follows the word of is the component-type of the array. The number of elements is 
determined by the index-type of the array, which must be an ordinal-type. 

If the component-type of an array-type is also an array-type, the result can be regarded as a single 
multi-dimensional array. An equivalent shorthand notation may be used to declare multi-dimen¬ 
sional arrays that entails declaring a single array with multiple index-types. For example, the type 

array [boolean] of array[1..10] of array[size] of real 

is equivalent to the type 

array[ boolean, 1..10, size ] of real 

where “equivalent” means that they will be interpreted in the same way. 

Examples of array-types: 

array [1..100] of real 
packed array [color] of boolean 

A component of an array can be accessed by referencing the array and supplying one or more 
indices (see §4.3.1). 

An array-type of the form 

packed array [l..n] of char 

is referred to as a packed-string-type with n components (in American National Standard Pascal 
these are called string-types; they are called packed-string-types here to avoid confusion with 
THINK Pascal’s string-types (see §3.3). A packed-string-type has certain properties not shared by 
other array-types or structured-types (see §§3.5 and 5.1.5). 


273 






THINK Pascal User Manual 


3.2.2 Record-Types 

A record-type consists of a fixed number of components called fields, each of which may be a 
different type. For each component, the record-type specifies the type of the field and an identifier 
that denotes it. 



The fixed-part of a record-type specifies a field-list that is always accessible in a variable of the 
record-type, giving an identifier and a type for each field. Each of these fields contains data that is 
always accessed in the same way (see §4.3.2). 

Example of a record-type: 

record 

year: integer; 

month: 1..12; 

day : 1. . 31 

end 


274 









Language Reference 


17 


A variant-part consists of alternative field-lists of which only one is accessible at a given time. 
Each alternative field-list is called a variant 

variant-part 



variant 



Each variant is preceded by one or more constants. All of the constants must be distinct and must 
be of an ordinal-type that is compatible with the tag-type (see §3.5). 

The variant-part allows for an optional identifier that denotes a tag-field. If a tag-field is present, it 
is considered a field of the fixed-part The value of the tag-field indicates which variant is active, 
and thus which variant’s fields are accessible at a given time. If there is no tag-field explicitly given, 
then all fields in all variants are always accessible, i.e. the active variant is the one containing the 
field most recently referenced. 

It is an error to alter the value of a tag-field while a reference to a field of the active variant exists. 
Whenever the value of the tag-field changes, the values of all of the fields in the newly active vari¬ 
ant are undefined. When the value of the tag-field is undefined, the values of all fields in all 
variants of the corresponding variant-part are undefined. 

Note: All of the variants of a variant-part share the same region of memory within 
a record variable. This is because only one particular variant is ever in use at a 
time (see also §10.1). 


273 










THINK Pascal User Manual 


It is not uncommon for Pascal programmers to use a variant-part with no explicit tag-field as a 
means of converting a value of one type to a value of another type, namely by assigning a value 
into a field of one variant and referencing the corresponding field in another variant. For example: 

var 

r: record 

case boolean of 

false: (CharVal: char); 
true: (IntVal: integer) 

end; 

r.CharVal := 'W'; 
c := r.IntVal; 


However, this kind of access assumes a knowledge of the underlying representation of variables in 
memory, and is therefore not recommended. This sort of type coercion should be performed using 
the predefined functions chr and ord, or with type casts (see §5.4) which are guaranteed to do 
what you would expect. 

Examples of record-types with variants: 

record 

name, firstName: string[80]; 
age: 0..9 9; 

case married: boolean of 

true: (spousesName: string[80]); 

false: () 

end 

record 

x,y: real; 
area: real; 
case s: shape of 
triangle: ( 

rectangle: ( 

circle: ( 

end 

3.2.3 Set-Types 

A set-type has a range of values that is the powerset of some ordinal-type, called the base-type. In 
other words, each possible value of a set-type is a subset of the possible values of the base-type. 


side: real; 

inclination, anglel, angle2: angle); 
sidel, side2 : real; 
skew, angle3: angle); 
diameter: real) 


set-type 



ordinal-type 


276 




Language Reference 


17 


Operators applicable to sets are specified in §5.1.4. §5.3 shows how set values are denoted in 
Pascal. 

The empty set (see §5.3) is a possible value of every set-type. 

3.2.4 File-Types 

A file-type is a structured-type consisting of a linear sequence of components that are all of one 
type, the component-type. The component-type may be any type that is not a file-type or a 
structured-type that contains a file-type component at any level of structuring. The number of 
components in a file-type variable is not fixed by the file-type declaration. 


file-type 




type 


The standard file-type text denotes a packed file of characters organized into lines. Files of type 
text are supported by the specialized I/O procedures discussed in §9.4. 

§4.3.3 and §9 discuss methods of accessing file components. 

3.2.5 Object-Types 

An object-type is similar to a record-type (§3.2.2) except that in addition to fields, object-types can 
contain components called methods. A method is a procedure or function that operates on the 
object. 

An object-type can be a descendant of any other object-type. It inherits all of the fields and meth¬ 
ods of its parent. A descendant object-type can defined new fields, new methods, and override 
inherited methods with its own implementation. 

Objects are created dynamically during program execution with the new and dispose procedures 
(§10.1.1 and §10.1.2). But instead of being identified by pointers, objects are identified by 
analogous values called references. 

A type identifier associated with an object type always denotes the reference type whose base type 
is that object type. 

A variable of type object is not the object itself, but rather a reference to the object. So a variable of 
type object is called a reference variable. A reference variable is said to possess reference-type. 
Any number of reference variables can refer to the same object. 

Note: This is analogous to how pointers work: a variable of type “pointer to inte¬ 
ger” is a pointer variable, not an integer. The pointer variable points to an integer. 

Several pointer variables can point to the same integer. 


277 




THINK Pascal User Manual 



heritage 


reference-type-identifier 



method-list 

-^ I method-heading 


V. 




reference-type-identifier 


identifier 


3.3 String-Types 

A string-type value is a sequence of characters that has a dynamic length attribute. The length is 
the actual number of characters in the sequence at any time during program execution. 

A string-type has a static size attribute that is an integral value in the range from 1 to 255. The size 
is a maximum limit on the length of any value of this type. If an explicit size attribute is not given 
for a string-type, then it is given a size of 255 by default. 


278 






Language Reference 


17 


The current value of the length attribute of a string-type value is returned by the standard function 
length (see §10.5.1). A null-string is a string-type value with a length of zero. 


Note: Do not confuse the size with the length. 
string-type 



The ordering relationship between any two string values is determined by lexical comparison 
based on the ordering relationship between character values in corresponding positions in the two 
strings. When the two strings are of unequal lengths, each character in the longer string that does 
not correspond to a character in the shorter one compares “higher”; thus the string value 
' attribute ' is greater than the value ' at'. Two strings must always have the same lengths to 
be equal; 'X ' (X followed by a space) is always greater than ' X 1 (just X). 

A null-string is only equal to another null-string and is less than every other possible string value. 

There are aspects of string-types that make it seem both a simple-type and a structured-type at the 
same time; it can therefore be considered neither. However, as explained in §4.3.1, individual char¬ 
acters in a string can be accessed as if they were components of an array. Operators applicable to 
strings are specified in §5.1.5. Standard procedures and functions for manipulating strings are 
described in §10.5. 

3.4 Pointer-Types 

A pointer-type defines a set of values that point to dynamic-variables of a specified type called 
the base-type. 

Pointer values are created by the standard procedure new (see §10.1.1), by the @ operator (see 
§5.1.6), and by the standard procedure pointer (see §10.2.4). 



279 










THINK Pascal User Manual 


The base-type may be an identifier that has not yet been declared. In this case, it must be declared 
somewhere in the same type-declaration-part as the pointer-type (see §2.2.3). 

The special symbol nil represents a standard pointer-valued constant that is a possible value of 
every pointer type. Conceptually, nil is a pointer that does not point to anything. 

§4.3 .4 discusses the syntax for referencing the object pointed to by a pointer variable. 

3.5 Identical and Compatible Types 

Two types may or may not be identical, and identity is required in some contexts. Other times, 
even if not identical, two types need only be compatible, and other times assignment- 
compatibility is required. 

3.5.1 Type Identity 

Identical types are required only in the following contexts: 

• For variable parameters, the actual and formal parameters must be identical types (see §7.3.2). 

• The result types of actual and formal functional parameters must be identical (see §7.3.4). 

• Value and variable parameters within parameter-lists of actual and formal procedural or 
functional parameters must be identical types (see §7.3.5). 

Two types, and T 2 , are identical if one of the following is true: 

• Ti and t 2 are the same type-identifier. 

• is declared to be equivalent to a type identical to T 2 . 

What the latter, somewhat circular statement implies is that need not be declared directly to be 
equivalent to T 2 ; thus the type-declarations 

T1 = integer; 

T2 = Tl; 

T3 = integer; 

T4 = T2; 

result in T lt T 2 , T 3 , T 4 , andinteger all being identical types. 

However, the type-declarations 

T5 = set of integer; 

T6 = set of integer; 

do not result in T 5 and T 6 being identical, since set of integer is not a type-identifier. 


280 



Language Reference 


17 


Finally, note that two variables declared in the same declaration, as in 
VI, V2: set of integer 

are of identical type. However, if the declarations are separate then the above definitions apply. 
The declarations 

VI: set of integer; 

V2: set of integer; 

V3: integer; 

V4: integer; 

result in v 3 and V 4 being of identical type, but not V x and V 2 . 

3.5.2 Compatibility of Types 

Compatibility between two types is sometimes required. Specific instances where type compatibil¬ 
ity is required are noted elsewhere in this manual. Type compatibility is, more importantly, often a 
precondition of assignment-compatibility. 

Two types are compatible if any of the following are true: 

• Both types are identical. 

• Both types are real-types. 

• Both types are integer-types. 

• One type is a subrange of the other. 

• Both types are subranges of identical host-types. 

• Both types are set-types with compatible base-types. 

• Both types are packed-string-types with the same number of components. 

• One type is a string-type and the the other is a string-type, packed-string-type, or char- 
type. 

3.5.3 Assignment-Compatibility 

Assignment-compatibility is required whenever a value is assigned to something, either explicitly 
(as in an assignment-statement) or implicitly (as in passing value parameters). 

A value V 2 of type T 2 is assignment-compatible with a variable V x of type T x (i.e. V x : =v 2 is 
permissible) if any of the following are true: 

• T x and t 2 are identical types and neither is a file-type or a structured-type that contains 
a file-type component at any level of structuring. 

• T x and t 2 are real-types and the value of type T 2 is within the range of possible values 
of T x . 

• T x is a real-type and T 2 is an integer-type. 

• T x and t 2 are compatible ordinal-types, and the value of type T 2 is within the range of 
possible values of T x . 

• T x and t 2 are compatible set-types, and all the members of the value of type T 2 are 
within the range of possible values of the base-type of T x . 


281 



THINK Pascal User Manual 


• T 1 and T 2 are compatible packed-string-types. 

• T 1 is a char-type and the value of type T 2 is a string-type and has a length of 1. 

• is a packed-string-type with n components and the value of type T 2 is a string-type 
and has a length of n. 

• T 1 is a string-type with a size of n and the value of type T 2 is a string-type and has a 
length less than or equal to n. 

• T 1 is a string-type with a size of n and the value of type T 2 is a packed-string-type with 
a number of components less than or equal to n. 

• T 1 is a string-type and T 2 is a char-type. 

• T 2 is a reference-type that inherits from T x . 

It is an error if assignment-compatibility is required and none of the above is true. 

3.6 The Type-Declaration Part 

Any program, procedure, or function that declares types contains a type-declaration-part, as 
shown in §2. 

Example of a type-declaration-part: 

type 


count 

= 

integer; 

range 

= 

integer; 

color 

= 

(red, yellow, green, blue) ; 

sex 

= 

(male, female); 

year 

= 

1900..1999; 

shape 

= 

(triangle, rectangle, circle); 

card 

= 

array [1..80] of char; 

str 

= 

string [80]; 

polar 

- 

record 


r: real; 
theta: angle 

end; 


person = ^personDetails; 
personDetails = record 

name, firstName: str; 

age: integer; 

married: boolean; 

father, child, sibling: person; 

case s: sex of 

male: (enlisted, bearded: boolean); 
female: (pregnant: boolean) 

end; 

people = file of personDetails; 
intfile = file of integer 


282 



Language Reference 


17 


In the above example count, range, and integer denote identical types. The type year is 
compatible and assignment-compatible with, but not identical to, the types range, count, and 
integer. 


4.0 Variables 

4.1 Variable-Declarations 

A variable-declaration consists of a list of identifiers denoting new variables, followed by their 
type. 


variable-declaration 

- ►! 


identifier-list 


}<>*[ 


The occurrence of an identifier within the identifier-list of a variable-declaration declares it as a 
variable-identifier for the block in which the declaration occurs. The variable can then be 
referenced throughout the remainder of that block, except as specified in §2.2.2. 

Examples of variable-declarations: 


x,y,z: real; 
i,j: integer; 
k: 0..9; 
p,q,r: boolean; 

operator: (plus, minus, times); 
a: array [0..63] of real; 
c: color; 
f: file of char; 
huel,hue2: set of color; 
pl,p2: person; 

m,ml,m2: array[1..10,1..10] of real; 
coord: polar; 

pooltape: array[1.. 4] of tape; 

4.2 Variable-References 

A variable-reference denotes either an entire variable, a component of a structured or string-type 
variable, a dynamic-variable pointed to by a pointer-type variable, or the file-buffer of a file-type 
variable. 


variable-reference 



283 








THINK Pascal User Manual 


4.3 Qualifiers 

As shown above, a variable-reference is a variable-identifier followed by zero or more qualifiers. 
Each qualifier modifies the meaning of the variable-reference. 


qualifier 

index 


-S 

H 

i 

field-designator | ■ 




—*o-► 

As an example, an array identifier with no qualifier is a reference to the entire array-variable: 
xResults 

If the array-identifier is followed by an index, this denotes a specific component of the array: 
xResults[current+1] 

If the component is a record, the index may be followed by a field-designator; in this case the 
variable-reference denotes a specific field within a specific array component. 

xResults[current+1].link 

If the field is a pointer, the field-designator may be followed by the symbol A to distinguish 
between the pointer field and the dynamic-variable being pointed to: 

xResults [current+1 ] . link'' 

If the object of the pointer is an array, another index can be added to denote a component of this 
array: 


xResults[current+1].link^ti] 
and so on... 

4.3.1 Arrays, Strings, and Indices 

A specific component of an array variable is denoted by a variable-reference that refers to the array 
variable, followed by an index that specifies the component. 


284 





Language Reference 


17 


A specific character within a string variable is denoted by a variable-reference that refers to the 
string variable, followed by an index that specifies the character position. 



Examples of indexed arrays: 

m[i,j] 
a [i + j] 

Each expression in the index selects a component in the corresponding dimension of the array. 

The number of expressions must not exceed the number of index-types in the array declaration. It 
is an error if the result of each expression is not assignment-compatible with the corresponding 
index-type. 

In indexing a multi-dimensional array, you can use either multiple indexes or multiple expressions 
within an index. The two forms are equivalent. For example, 

m[i] [j] 

is equivalent to 

m[i f j] 

A string value can be indexed by only one index expression, whose value must be in the range 
1. . n, where n is the current length of the string value. The effect is to access one character of the 
string value, and the type of the character value accessed is char. 

Any value assigned to a component-variable of an array or string must be assignment-compatible 
with the component-type. 

When a string value is manipulated by assigning values to individual character positions, the length 
of the string is not affected. It is an error to access a character position in a string variable with an 
index less than one or greater than the length of the string variable. For example, suppose that 
strval has been declared as follows: 

strval: stringflO]; 

and that the assignment: 

strval := 'abcde 1 ; 

has been performed. A reference to: 

strval[0] 


285 




THINK Pascal User Manual 


would be an error since the reference contains an index less than 1. Likewise, a reference to: 
strval[6] 

would be an error since the index is greater than the current length of the string. Note that these 
references would still be errors even if they occurred on the left-hand side of an assignment state¬ 
ment. To add a character or string to the end of another string, or to manipulate strings in other 
ways, use the standard procedures described in §10.5. 

Note also that, when a program, procedure, or function block is entered, the length of a string vari¬ 
able is initially undefined. Therefore, the manipulation of string variables with indexes before string 
values have been assigned to these variables can lead to unpredictable results. 

4.3.2 Records and Field-Designators 

A specific field of a record variable is denoted by a variable-reference that refers to the record 
variable, followed by a field-designator that specifies a field of the record. 

field-designat or 


Examples of field-designators: 

p2^.pregnant 
coord.theta 

It is an error if the field-designator refers to a field in a variant that is not active (see §3.2.2). 

Note that a field-designator need not be preceded by a variable-reference to its containing record in 
a statement within a with statement (see §6.2.4). 

Fields of an object are accessed with a reference variable (§3.2.5) rather than with a record variable. 
You can leave out the reference variable and the inside a with statement. You can also leave 
out the reference variable in a method block; in this case it is the same as having written self. 
before the field name (see §6.1.2 and §7.3.6). 

4.3.3 File-Buffers 

Although a file-variable may have any number of components, only one component is accessible 
at any time. The position of the current component in the file is called the current file position. 
Program access to the current component is via a special variable associated with the file, called a 

file-buffer. 

The file-buffer is implicitly declared when the file variable is declared. If f is a file variable with 
components of type t, then the associated file-buffer is a variable of type t. 


identifier 


The file-buffer associated with a file variable is denoted by a variable-reference that refers to the file 
variable, followed by the A symbol. Thus, the file-buffer of file f is referenced by f T 




Language Reference 


17 


§9 describes standard procedures that move the current file position within the file and to transfer 
data between the file-buffer and the current file component. 

4.3.4 Pointers, Reference-Variables, and Dynamic-Variables 

The value of a pointer variable is either nil, or a value that points to a dynamic-variable. 

The dynamic-variable pointed to by a pointer variable is denoted by a variable-reference that refers 
to the pointer variable followed by the * symbol. 

Dynamic-variables and pointer values that point to them are created by the standard procedure 
new (see §10.1.1). Additionally, the @ operator (see §5.1.6) and the standard procedure pointer 
(see §10.2.4) may be used to create pointer values that are not in fact pointers to dynamic-variables, 
but that will be treated as such. 

The constant nil (see §3.4) does not point to any object. It is an error if you access a dynamic- 
variable when the pointer’s value is undefined or is nil. 

Examples of references to dynamic-variables: 

Pl A 

pl A .siblings 

Note: Although the * symbol is used to reference both file-buffers and dynamic- 
variables, this does not mean that a file variable can be treated like a pointer. 

Specifically, ord (f), where f is a file variable reference, does not yield an 
address value (see §10.4.1). It is, in fact, an error. 

A variable of type object is a reference variable. There is no way to reference the object itself, 
only the fields of an object. That is, you can’t use the A operator to access the object. 

5.0 Expressions 

Expressions consist of operators and operands. Most operators in Pascal are binary, i.e. they 
take two operands; the rest are unary and take only one operand. The binary operators and their 
operands are denoted in the common algebraic fashion: the operands are given with the operator 
to act upon them in between, e.g., a+b. A unary operator is always immediately followed by its 
operand. 

When more complex expressions are written, certain rules must be applied to determine which 
operands are associated with which operators. For instance, the expression: 

a+b*c 

can be interpreted as either (a+b) *c or a+ (b*c). The precedence rules makes the in¬ 
terpretation unambiguous: 

• When an operand appears between two operators of different precedence, it is bound 
to the operator with the higher precedence. 


287 



THINK Pascal User Manual 


• When an operand is written between two operators of the same precedence, it is bound 
to the operator to the left 

• A parenthesized expression is always evaluated before it is applied as an operand 
Table 5-1 gives the precedence of the binary and unary operators: 


Table 5-1 Precedence of Operators 


Operators 

Precedence 

Category 

not 

first (highest) 

unary operators 

*, /, div, mod, and 

second 

“multiplying” operators 

+, or 

third 

“adding” operators & signs 

=, <>, <, >, <=, >=, in 

fourth Go west) 

relational operators 


Thus, a+b*c is interpreted as a+ (b*c), since * has a higher precedence than + , and a+b-c is 
interpreted as (a+b) -c, since + and - have the same precedence. precedence rules 

The range of an operator is not infinite. For instance, if a, b, and c are integer-type integer val¬ 
ues, and if a+b yields a value greater than maxint, then the evaluation (a+b) -c will result in an 
error whereas a+ (b-c) may not Whenever the order of evaluation of operators is critical, or is 
otherwise in doubt, parentheses may always be used to force a specific order. 

Also be aware that, because the relational operators have the lowest precedence, an expression 
such as 

a<b or c<d 

is wrong because the precedence rules interpret the expression as 
a < (b or c) < d 

which is not a valid expression (see below). Thus, such an expression must be written as 
(a<b) or (c<d) 

The precedence rules are implicit from the syntax for expressions, which are built up from factors, 
terms, and simple-expressions. 


288 




The syntax for a factor allows the unary operators @ and not to be applied to a value: 


factor 


variable-reference 


procedure-identifier 


function-identifier 


unsigned-constant 


function-call 


set-constructor 


expression 


factor 


type-cast 


A function-call activates a function, and denotes the value returned by the function (see §5.2). A 
set-constructor denotes a value of a set-type (see §5.3). An unsigned-constant has the following 
syntax: 


unsigned-constant 


unsigned-number 


quoted-string-constant 


constant-identifier 


Examples of factors: 


x {variable-reference} 

@x {pointer to a variable} 

15 {unsigned-constant} 

(x+y+z) {sub-expression} 

sin(x/2) {function-call} 

[ , A , .. , F , r , a , .. , f l ] {set-constructor} 

not p {negation of a boolean} 

























THINK Pascal User Manual 


The syntax for a term allows the “multiplying* operators to be applied to factors: 



Examples of terms: 
x*y 

i/(1-i) 

p and q 

(x <= y) and (y < z) 

The syntax for a simple-expression allows the “adding” operators and signs to be applied to 
terms: 










Language Reference 


17 


The syntax for an expression allows the relational operators to be applied to simple-expressions: 
expression 



Examples of expressions: 

x = 1.5 

P <= q 
p = q and r 
(i < j) = (j < k) 
c in huel 

5.1 Operators 

This section describes the Pascal arithmetic, relational, and address operators. 

5.1.1 Binary Operators: Order of Evaluation of Operands 

The order in which the operands of a binary operator are evaluated is unspecified. 

A function, in the normal case, simply returns a value. However, a function may also alter the value 
of variables as a side-effect Therefore if a function is one operand of a binary operator, and if it 
modifies the value of the other operand, then the evaluation of the operator may lead to unpre¬ 
dictable results. For instance, if a call to a function f (x) modifies the value of x, then the evalua¬ 
tion of x+f (x) may yield an unexpected result depending on whether or not f (x) is evaluated 
before the x to the left of the +. 


291 





THINK Pascal User Manual 


5.1.2 Arithmetic Operators 

The types of operands and results for arithmetic binary and unary operations are shown in Tables 
5-2 and 5-3 respectively. 


Table 5-2 Binary Arithmetic Operations 


Operation 

Operand Types 

Result Type 

+ addition 

subtraction 

* multiplication 

integer integer 

integer longint 

longint longint 

real-type any type 

integer 

longint 

longint 

extended 

/ division 

any type any type 

extended 

div integer division 

integer integer 
integer longint 
longint longint 

integer 

longint 

longint 

mod modulo 

integer integer 
integer longint 
longint longint 

integer 

longint 

longint 


Note: The symbols +, and * are also used as set operators. See Section 5.1.4. 


Table 5-3 Unary Arithmetic Operations 


Operation 

Operand Type 

Result Type 

+ identity 

integer 

integer 

negation 

longint 

longint 


real-type 

extended 


Any operand whose type is subr, where subr is a subrange of some ordinal host-type ordtyp, is 
treated as if it were of type ordtyp. Consequently, an expression that consists of a single operand 
of type subr is itself of type ordtyp. 

If both operands of the addition, subtraction, or multiplication operators are of the integer-type 
integer, the result is always of type integer and has a value determined by the normal mathe¬ 
matical rules for integer arithmetic. It is an error if the value of the result is outside the range 
-maxint-1. .maxint. 

If one or both operands of the addition, subtraction, or multiplication operators are of the integer- 
type longint, the result is always of type longint and has a value determined by the normal 
mathematical rules for integer arithmetic. It is an error of the value if the result is outside the range 
-maxlongint-1..maxlongint. 

If one of the operands of the addition, subtraction, or multiplication operators is of a real-type, the 
result is always of type extended and has a value that is an approximation of the normal mathe¬ 
matical result. It is an error if the result is outside the range of values representable with the real- 
type extended (see §3.1.2). 


292 





Language Reference 17 


Note: See Apple Numerics Manual, Second Edition (Addison-Wesley) for more 
information on all arithmetic operations with operands or results of a real-type. 

If the operand of the identity or sign-negation operator is of the integer-type integer, the result is 
always of type integer and the absolute value of the result is always identical to the absolute 
value of the operand. 

If the operand of the identity or sign-negation operator is of a real-type, the result is always of type 
extended and the absolute value of the result is always identical to the absolute value of the 
operand. 

If the operand of the identity or sign-negation operator is of the integer-type longint, the result is 
always of type longint and the absolute value of the result is always identical to the absolute 
value of the operand. 

The value of i / j is always of type extended and has a value that is an approximation of the 
normal mathematical result. It is an error if the result is outside the range of values representable 
with the real-type extended (see §3.1.2). It is an error if j=0. 

If the operands of the div operator are of the integer-type integer, the result is always of type 
integer, and the value of i div j is the mathematical quotient of i / j, rounded toward zero. It 
is an error if j = 0 . 

If one or both of the operands of the div operator are of the integer-type longint, the result is 
always of type longint, and the value of i div j is the mathematical quotients of i/j, 
rounded toward zero. It is an error if j = 0. 

The mod operator is defined as: 

i mod j = i - (i div j) * j 

5.1.3 Boolean Operators 

The types of operands and results for Boolean operations are shown in Table 5-4. 


Table 5-4 Boolean Operations 


Operation 

Operand Type 

Result Type 

or disjunction 

and conjunction 

not negation 

boolean 

boolean 


The result of a boolean operation is determined by the normal rules of boolean logic, e.g. a and 
b evaluates to true if and only if both a and b are true. 


293 




THINK Pascal User Manual 


Boolean operators are somewhat unique in that the result of the operation may often be de¬ 
termined by the examination of only one operand For example, the expression 

(b<>0) and (a/b>lO) 

is known to have the value false if b=0 regardless of the value of a. However, the evaluation of 
the subexpression (a /b>l 0) may or may not be performed in the evaluation of this expression. 
It is therefore best to assume that it will and avoid this kind of expression. On the other hand, if an 
operand of a boolean expression is a function with side-effects (i.e. it modifies a variable as well as 
returns a value), there is no guarantee that the function will be activated if the result of the opera¬ 
tion can be determined solely by the evaluation of the other operand. It is therefore best to also 
avoid such expressions. 

5.1.4 Set Operators 

The types of operands and results for set operations are shown in Table 5-5. 


Table 5-5 Set Operations 


Operation 

Operand Type 

Result Type 

+ union 

difference 

* intersection 

compatible set types 

(see below) 


The order of evaluation of member-groups and of expressions within member-groups is un¬ 
specified. 

The results of the set operations are determined by the normal rules of set logic. 

• An ordinal value c is in the set a+b if and only if c is in a or in b. 

• An ordinal value c is in the set a-b if and only if c is in a and not in b. 

• An ordinal value c is in the set a*b if and only if c is in a and in b. 

Given the result of a set operation, if the smallest ordinal value that is a member of that result is a 
and if the largest ordinal-value that is a member of the result is b, then the type of the result is set 
of a..b. 


294 




Language Reference 


17 


5.1.5 Relational Operators 

The types of operands and results for relational operations are shown in Table 5-6. 


Table 5-6 Relational Operations 


Operation 

Operand Type 

Result Type 

= equal to 

<> not equal to 

One of the following: 

• Compatible simple types 

• Compatible string types 

• Compatible packed-string 
types 

• Compatible pointer types 

• Compatible set types 

boolean 

< less than 

> greater than 

<= less than or equal to 

>S£ greater than or equal to 

One of the following: 

• Compatible simple types 

• Compatible string types 

• Compatible packed-string 
types 

boolean 

<= subset of 

>= superset of 

Compatible set types 

boolean 

in member of 

(See section 5.1.5.7) 

boolean 


5.1.5.1 Comparing Ordinals 

When the operands of =, <>, <, >, >=, or <= are of an ordinal-type, they must be of 
compatible types. The result is the mathematical relation of their ordinalities. 

5.1.5.2 Comparing Reals 

When one operand of=, <>, <, >, >=, or <= is of a real-type, the other must be of a real- 
type or an integer-type. The result is the mathematical relation of the values represented as 
extended type values. 

Because real-type values are only approximations, the results of these operations may not always 
be as expected. For instance, if aReal is a variable of type real and aDouble is a variable of 
type double, and if the assignments 

aReal := 1/3; 
aDouble := 1/3; 

have been performed, then the relation aReal=aDouble will return false. This is because the 
value of aReal is a representation of 1/3 to only 7-8 decimal digits and the value of aDouble is a 
representation of 1/3 to 15-16 decimal digits. Since the decimal (and even the binary) representa¬ 
tion of 1/3 is a repeating sequence of digits, the 8 low-order decimal digits of aDouble will differ 
from the corresponding digits of aReal (when converted to extended), which will always be 
zero. 


295 




THINK Pascal User Manual 


See Apple Numerics Manual, Second Edition (Addison-Wesley) for more information on relational 
operations with operands of real-type. 

5.1.5.3 Comparing String 

When the relational operators =, <>, <, >, >=, and > are used to compare strings (see 
§3.3), they denote lexicographic ordering according to the ordering of the Macintosh character set 
Note that any two string values can be compared since all string values are compatible. 
Additionally, a char value is compatible with a string-type value, and when the two are compared, 
the char value is treated as a string-type value with length 1. When a packed-string-type value 
with n components is compared with a string-type value, it is treated as a string-type value with 
length n. 

5.1.5.4 Comparing Packed-Strings 

The relational operators = , <>, <, >, <=, and >= can also be used to compare two values 
of a packed-string-type if both have the same number of components. If that number of compo¬ 
nents is n, then the result is the same as if the values were string-type with each having a length of 
n. 

5.1.5.5 Comparing Sets 

If a and b are set operands, then 

• a=b is true if and only if every member of a is a member of b and every member of b is 
a member of a; otherwise, a<>b. 

• a<=b is true if and only if every member of a is also a member of b. 

• a>=b is true if and only if every member of b is also a member of a. 

Thus, a=b and a<>b denote the equivalence and non-equivalence of the sets a and b respectively, 
and a<=b and a>=b denote the inclusion of a in b and the inclusion of b in a respectively. 

5.1.5.6 Comparing Pointers 

The relational operators = and <> may be applied to compatible pointer-type operands. Two 
pointers are equal if and only if they point to the same object. 

5.1.5.7 Testing Set Membership 

The in operator yields the value t rue if the value of the ordinal-type operand is a member of the 
set-type operand; otherwise it yields the value false. The type of the left operand must be 
compatible with the base-type of the right operand. 

5.1.6 The Q Operator 

A pointer value that points to a variable, procedure, or function can be created with the @ operator. 
The operand and result types are shown in Table 5-7. 


296 



Language Reference 


17 


@ is a unary operator taking a single variable-reference or a procedure or function identifier as its 
operand and computing the value of its pointer. The type of the value is equivalent to the type of 
nil, i.e. it can be assigned to any pointer variable. 


Table 5-7 Pointer Operation 


Operation 

Operand Type 

Result Type 

@ pointer formation 

One of the following: 

• Variable reference 

• Procedure identifier 

• Function identifier 

same as nil 


The @ operator is not a standard feature of Pascal, and its indiscriminate use is not recommended. It 
is intended to be used in conjunction with the Macintosh Toolbox routines. 

5.1.6.1 The 9 Operator with a Variable 

For an ordinary variable (not a parameter), the use of @ is straightforward. For example, if we have 
the declarations 

type 

twochar = packed array[0..1] of char; 

var 

int: integer; 
twocharptr: A twochar; 

then the statement 

twocharptr := @int 

causes twocharptr to point to int. Now twocharptr'" is a reinterpretation of the bit value of 
int as though it were a packed array [ 0 . . 1 ] of char. 

The operand of @ cannot be applied to a component of a packed variable. 

5.1.6.2 The 9 Operator with a Value Parameter 

When @ is applied to a formal value parameter, the result is a pointer to the location containing the 
actual value, which is on a run time stack. Suppose that f oo is a formal value parameter in a 
procedure and f ooptr is a pointer variable. If the procedure executes the statement 

fooptr := @foo 

then fooptr 7 " is a reference to the value of f oo. Note that if the actual-parameter is a variable-ref¬ 
erence, fooptr 7 " is not a reference to the variable itself; it is a reference to the value taken from 
the variable and stored on the stack. 


297 




THINK Pascal User Manual 


5.1.6.3 The 9 Operator with a Variable Parameter 

When @ is applied to a formal variable parameter, the result is a pointer to the actual-parameter. 
Suppose that f um is a formal variable parameter of a procedure, fie is a variable passed to the 
procedure as the actual-parameter for fum, and fumptr is a pointer variable. 

If the procedure executes the statement 

fumptr := @furn 

then fumptr is a pointer to fie and fumptr* is a reference to fie itself. 

5.1.6.4 The 9 Operator with a Procedure or Function Identifier 

It is possible to apply @ to a procedure or a function, yielding a pointer to the procedure’s or func¬ 
tion’s entry-point This pointer actually points to a jump table entry for the routine. See Chapter 
13 for more information. 

THINK Pascal provides no mechanism for using such a pointer. The typical use for a procedure 
pointer is to pass it to a Macintosh Toolbox routine. The @ operator can not be applied to 
predefined, inline, Toolbox, or nested routines. 

5.2 Function-Calls 

A function-call specifies the activation of the function denoted by the function-identifier. The result 
returned by the function activation is subsequently used as an expression value. If the correspond¬ 
ing function-declaration contains a list of formal-parameters, then the function-call must contain a 
corresponding list of actual-parameters. Each actual-parameter is substituted for the corresponding 
formal-parameter as described in §7.3. 


function-call 



Note: method-designator is defined in §6.1.2 
actual-parameter-list 



298 







Language Reference 


17 



A function-identifier is any identifier that has been declared to denote a function. 

Examples of function-calls: 

sum (a, 63) 
gcd(147,k) 
sin(x+y) 
eof(f) 
ord(f^) 

5.2.1 Using function calls in 1-value contexts 

You can use function calls and method calls in l-value contexts. L-value contexts include 

• The left-hand side of an assignment statement 

• An argument to a with statement 

• A method call. 

For example: 
const 

WindowList = $09D6; 
function GetListHead: ListElementPtr; 

begin 

nextWindow := WindowPeek(WindowList)*.nextWindow; 
GetListHead"'.nextElement := nil; 

with GetListHead"' do 

end; 


299 







THINK Pascal User Manual 


Inside a function, be careful when you call the function in an 1-value context recursively. If the 
function name is qualified by BA ", the function is called recursively and the qualifier is applied to 
the return value. If the function name isn’t qualified or is qualified by “." or “[...] ”, THINK Pascal 
assumes you are assigning the return value. For example: 

function Foo: Ptr; 
begin 

Foo := @Bar; 

Foo A := 0; 

end; 

5.3 Set-Constructors 

A set-constructor denotes a value of a set-type, and is formed by writing expressions within 
[brackets ] . Each expression denotes a value of the set. 



{ Makes @Bar the function's return value. ) 
{ Calls Foo recursively and assigns 0 to } 
{ the byte that the result points to. } 


member-group 


expression 



expression 



The notation, [ ] denotes the empty set, which is assignment-compatible with every set-type. Any 
member-group x. . y denotes as set members all values in the range x. . y. If the value of x is 
greater then the value of y, then x. . y denotes no members and [x. . y ] denotes the empty set. 

All expression values in the member-groups of a particular set-constructor must be of compatible 
ordinal-types. If a is the smallest ordinal-value in the resulting set, and if b is the largest ordinal- 
value in the resulting set, then the base-type of the resulting set is a. . b. 

Examples of set-constructors: 

[red f c, green] 

[l f 5, 10..k mod 12, 23] 

[ , A , .. , Z , r ' a ' . . 1 z 1 , chr (xcode) ] 


300 






Language Reference 17 


5.4 Type-Casts 

Type casting (also called type coercion) provides a way to change the type of an expression to 
another type. 



For ordinal and pointer types, the result of this operation is an expression of type type-identifier 
whose (ordinal) value is obtained by converting the original expression. This conversion may in¬ 
volve truncation or extension of the original value if the storage size of the expression is changed. 

For non-ordinal types, the result of this operation is an expression of type type-identifier whose 
internal representation (i.e., the pattern of bits which comprise its value) is the same as the internal 
representation of the original expression. In particular, the storage size of a (non-ordinal) 
expression may not be changed by a type cast. 

A value of reference-type can be coerced to another reference-type in the same domain. 

Examples of type-casts: 

boolean (1) 
ptr (longint(p)+1) 
ptr (-1) 
longint (@proc) 
color (x) 
point (0) 

6.0 Statements 

Statements denote algorithmic actions, and are executable. They can be prefixed by labels and a 
labeled statement can be referenced by a goto-statement. 


statement 



A digit-sequence used as a label must be in the range 0..9999, and must first be declared as 
described in §2.1. 


301 









THINK Pascal User Manual 


6.1 Simple-Statements 

A simple-statement is a statement that does not contain any other statement. 



6.1.1 Assignment-Statements 

The syntax for an assignment-statement is as follows: 


assignment-statement 



The assignment-statement can be used in two ways: 

• To replace the current value of a variable with a new value specified by an expression. 

• To specify an expression whose value is to be returned by a function. 

The expression must be assignment-compatible with the type of the variable or the result-type of 
the function as described in §3.5.3. 

It is not specified whether the variable-reference is evaluated before or after the evaluation of the 
expression. However, once the reference is established, it is not altered by the remaining execution 
of the assignment-statement. Thus, the outcome of 

a [x] : = f (x) 

depends on whether f modifies x and, if so, whether f (x) is evaluated before or after a [x] . 
Examples of assignment-statements: 
x := y+z; 

p := (l<=i) and (i<100); 
i := sqr(k) - (i*j); 
huel := [blue,succ(c)] 

6.1.2 Procedure-Statements 

A procedure-statement specifies the activation of the procedure denoted by the procedure-iden¬ 
tifier. If the corresponding procedure-declaration contains a list of formal-parameters, then the pro¬ 
cedure-statement must contain a corresponding list of actual-parameters. Each actual-parameter is 
substituted for the corresponding formal-parameter as described in §7.3. 


302 






Language Reference 


17 


A method-designator activates the method specified by the method-identifier (§3.2.5) of an ob¬ 
ject-type referenced by the reference-variable. The actual method activated is specified by the run¬ 
time type of the object. When the method is activated, the object is passed as an implicit formal 
parameter called self (see §7.3.6) of the type corresponding to the object whose method was 
activated. 

You can omit the reference variable and the within a with statement that lists the reference 
variable (see §4.3.2 and §6.2.4). You can also leave out the reference variable in a method block; in 
this case it is the same as having written self. before the field name. 

You’ll usually use the inherited keyword when you override a method (see §3.2.5). It can only 
be used in a method block. When it appears before a method-identifier, it causes self to be the 
implicit actual parameter to the called procedure. The method activated is always the method in¬ 
herited from the parent object; any overrides are ignored. 


procedure statement 



A method-designator activates the method specified by the method-identifier (§3.2.5) of an 
object. The run-time type of the object determines which method is activated. 


method-designator 


reference-variable 


]-GH 


Inherited 


> 


H method-identifier 


Note; The order in which actual parameters are evaluated and bound to their 
formal parameters is unspecified. 

Examples of procedure-statements: 

PrintHeading; 

Transpose(a,n,m) ; 

Bisect(fct,-1.0,+1.0,x) 

6.1.3 Goto-Statements 

A goto-statement causes the statement prefixed by the label that is referenced in the goto- 
statement to be the next statement executed. 


303 






THINK Pascal User Manual 


goto-statement 


< goto 


label 


Note: The constants that introduce cases within a case-statement (see §6.2.2.2) are 
not labels, and cannot be referenced in goto-statements. 

A goto-statement G can goto a labeled statement S if and only if one of the following is true: 

• S is a statement that contains G. For example: 

1: if ... then 

2: begin 

3: begin 

goto {1, 2 and 3 are legal, 4 is not) 

end 

end 

else 

4: begin 

end 

• S is a statement of a statement-list that contains G. For example: 

begin 

1: 

begin 

2: 

begin 

goto {l r 2, 3, and 4 are legal, 5 is not) 

end 


end 


end; 

begin 

5: ... 

end 


304 





Language Reference 


17 


• S is a statement in a block that contains the block containing G, provided that S is a statement of 
the outermost statement-list of its block. For example: 
program a (...) ; 

procedure b; 

procedure c; 
begin 

goto [2 and 4 are legal; 1 and 3 are not} 

end; 

procedure d; 
begin 


1: 



end; 


begin { b } 

2 : 

••• f 


begin 

3: 

... 


end 


begin { main } 

4 : ... 

end. 

When the destination of a goto is in a block b that does not contain the goto, every block 
activation (see §2.3) that has occurred since the most recent activation of b is terminated. 

6.2 Structured-Statements 

Structured-statements are made up of of other statements that are to be executed either condi¬ 
tionally (conditional-statements), repeatedly (repetitive-statements), or in sequence (compound- 
statement or with-statement). 



305 







THINK Pascal User Manual 


6.2.1 Compound-Statements 

The compound-statement specifies that its component statements are to be executed in the same 
sequence as they are written. The semicolon is a statement separator, not terminator. 


compound-statement 



Example of compound-statement: 


begin 

z : = x ; 
x := y; 
y := z 

end 

An important use of the compound-statement is to group more than one statement into a single 
statement in contexts where the Pascal syntax only allows one statement. The symbols begin and 
end act as “statement brackets.” Examples of this will be seen in §6.2.3.2. 

6.2.2 Conditional-Statements 

A conditional-statement selects for execution a single one (or none) of its component 
statements. 



306 








Language Reference 


17 


6.2.2.1 If-Statements 

The syntax for if-statements is: 



The expression must yield a result of the standard type boolean. If the expression yields the value 
true, then the statement following the then is executed. 

If the expression yields false, and the else part is present, the statement following the else is 
executed; if the else part is not present, then execution proceeds with the next statement 
following the if statement. 

The syntactic ambiguity arising from something like: 

if el then if e2 then si else s2 

is resolved by interpreting it as being equivalent to: 

if el then 
begin 

if e2 then 

si 

else 

s2 

end 

rather than: 

if el then 
begin 

if e2 then 

si 

end 

else 

s2 

In other words, an else is always associated with the closest if that is not already associated with 

an else. 


307 






THINK Pascal User Manual 


Examples of if-statements: 

if x < 1.5 then 

z := x+y 

else 

z := 1.5 

if pi <> nil then 

pi := pi'', father 

6.2.2.2 Case-Statements 

The case-statement contains an expression (the selector) and a list of statements. Each statement 
must be prefixed with one or more constants (called case-constants), or with the reserved word 
otherwise. All the case-constants must be distinct and must be of an ordinal-type that is 
compatible with the type of the selector. A case-constant can be of type longint. 


case-statement 



The case-statement specifies execution of the statement prefixed by a case-constant equal to the 
current value of the selector. If no such case-constant exists and an otherwise part is present, the 
statement following the word otherwise is executed; if no otherwise part is present, it is an 
error. 


308 










Language Reference 


17 


Examples of case-statements: 


case operator of 

plus: 

x : = x+y; 

minus: 

x := x-y; 

times: 

end 

x := x*y 

case i of 

1: x : = 

o n -l o 

sin(x); 


2.8.. 12: x := cos(x); 

3.. 7: x := exp(x); 

otherwise 

x := In(x) 

end 

6.2.3 Repetitive-Statements 

Repetitive-statements specify that certain statements are to be executed repeatedly. 



6.2.3.1 Repeat-Statements 

A repeat-statement contains an expression that controls the repeated execution of a sequence of 
statements contained within the repeat-statement. 


re peat-statement 


-x repeat j-m: statement-list x until >1 expression 


The expression must yield a result of the standard type boolean. The statements between the 
symbols repeat and until are repeatedly executed in sequence until, at the end of a sequence, 
the expression yields the value true. The sequence of statements is executed at least once, 
because the expression is evaluated after the execution of each sequence. 

Examples of repeat-statements: 


repeat 

k : = i mod j ; 
i : = j; 
j := k 

until j = 0 


309 








THINK Pascal User Manual 


repeat 

process(f*) ; 
get (f) 

until eof(f) 

6.2.3.2 While-Statements 

A while-statement contains an expression that controls the repeated execution of a statement 
(which may be a compound-statement). 


while-statement 


while 


expression 


statement 


The expression must yield a result of the standard type boolean. It is evaluated before the con¬ 
tained statement is executed. The contained statement is repeatedly executed as long as the ex¬ 
pression yields the value true. If the expression yields false at the beginning, the statement is 
not executed. 

The while-statement: 

while b do 

body 

is equivalent to: 

if b then 
repeat 

body 

until not b 

Examples of while-statements: 

while a[i] <> x do 
i := i+1 

while i>0 do 
begin 

if odd ( i ) then 
z := z*x; 
i := i div 2; 
x := sqr(x) 

end 

while not eof(f) do 
begin 

process(f*); 
get(f) 

end 


310 





Language Reference 


17 


6.2.33 For-Statements 

The for-statement causes a statement (possibly a compound-statement) to be repeatedly executed 
while a sequence of values is assigned to a variable called the control-variable. 



control —va ri abl e 


1 . 


variable - identifier 

M 



The control-variable must be a variable-identifier (without any qualifier) denoting a variable that is 
declared to be local to the block containing the for-statemenL The control-variable must be of an 
ordinal-type, and the initial and final values must be of a type assignment-compatible with this 
type. 

On entering a for-statement, the initial-value and the final-value are determined once (and only 
once) for the remainder of the execution of the for-statement. 

Loosely speaking, the statement contained by the for-statement is executed once for every value in 
the range initial-value. . final-value. With a for-statement using to, the control-variable 
has the value initial-value the first time, succ (initial-value) the second time, and so on. If 
the initial-value is greater than the final-value, then the contained statement is not executed. With a 
for-statement using downto, the control-variable has the value initial-value the first time, 
pred (initial-value) the second time, and so on. If the initial-value is less than the final- 
value, then the contained statement is not executed. 

It is an error if the value of the control-variable is altered by execution of the contained statement. 
After a for-statement is executed, the value of the control-variable is undefined, unless the 
execution of the for-statement was terminated by a goto out of the for-statement. 


311 










THINK Pascal User Manual 


Apart from these restrictions, the for-statement: 

for v := el to e2 do 
body 

is equivalent to: 

begin 

tempi := el; 
temp2 := e2; 
if tempi <= temp2 then 
begin 

v : = tempi; 
body ; 

while v <> temp2 do 

begin 

v := succ (v); 
body 

end 

end 

end 

and the for-statement: 

for v := el downto e2 do 
body 

is equivalent to: 

begin 

tempi := el; 
temp2 := e2; 
if tempi >= temp2 then 
begin 

v := tempi; 
body ; 

while v <> temp2 do 

begin 

v := pred(v); 
body 

end 

end 

end 

where tempi and temp2 are auxiliary variables of the host-type of the variable v that do not occur 
elsewhere in the program; they are used to resolve the expressions el and e2 upon entering the 
statement’s body. 


312 



Language Reference 17 


Examples of for-statements: 

for i := 2 to 63 do 

if a[i] > max then 
max := a[i] 

for i := 1 to n do 

for j := 1 to n do 
begin 

x : = 0; 

for k := 1 to n do 

x := x + ml [i, k] *m2 [k, j ] ; 
m[i,j] := x 

end 

for c := red to blue do 
q(c) 

6.2.4 With-Statements 

The syntax for a with-statement is 


with-statement 



with-variable-list 



The occurrence of a record-variable-reference or a reference-variable in a with-statement affects the 
way the compiler processes variable-references within the statement following the word do. Within 
a with-statement, fields of the record-variable or the reference-variable can be referenced directly 
by their field-identifiers, without making explicit reference to the record-variable. The same is true 
for methods of reference-variables. 


313 




THINK Pascal User Manual 


Example of a with-statement: 

with date do 

if month = 12 then 
begin 

month :* 1; 
year := year + 1 

end 

else 

month := month +1; 

This is equivalent to: 

if date.month = 12 then 
begin 

date.month := 1; 

date.year := date.year +1 

end 

else 

date.month := date.month + 1 

Within a with-statement, each variable-reference is checked to see if it can be interpreted as a field 
of the record. If so, it is always interpreted as such, even if a variable with the same name is 
accessible also. For instance, suppose that we have the following declarations: 

type 

recTyp = record 
foo: integer; 
bar: real; 

end; 


var 

bar: recTyp; 
foo: integer; 

The identifier foo can refer both to a field of the record variable bar and to a variable of type 
integer. In the statement 

with bar do 
begin 

foo := 36; 
bar := 2.5; 


end 

the bar between the with and the do is a reference to the variable bar, but foo is a reference to 
the field bar. foo, not the variable foo. Likewise, the reference to bar within this with-statement 
refers to bar. bar. 

314 



Language Reference 17 


The statement; 

with v lf v 2 , ... v n do 
s 

is equivalent to: 

with v 1 do 

with v 2 do 

with v n do 

s 

Thus, if v n in the above statements is a field of both v 1 and v 2 , it is interpreted to mean v 2 . v n 
and not . v n . 

If the selection of a variable in the record-variable-list involves the indexing of an array or the de¬ 
referencing of a pointer, these actions are executed only once before the component statement is 
executed. 

7.0 Procedures and Functions 

This section describes how to declare procedures and function in Pascal. It also describes how 
Pascal interprets parameters passed to these routines. 

7.1 Procedure-Declarations 

A procedure-declaration associates an identifier with a block as a procedure so that it can be 
activated by a procedure-statement (see §6.1.2). 

procedure-declaration 



315 






THINK Pascal User Manual 


The procedure-heading specifies the identifier for the procedure, and the formal parameters (if 
any). 


procedure-heading 



The syntax for a formal-parameter-list is given in §7.3. 

A procedure is activated by a procedure-statement (see §6.1.2), which gives the procedure’s identi¬ 
fier and any actual-parameters required by the procedure. The statements to be executed upon ac¬ 
tivation of the procedure are specified by the statement-part of the procedure’s block. If the proce¬ 
dure’s identifier is used in a procedure-statement within the procedure’s block, the procedure is 
executed recursively (see §2.3). 

Example of a procedure-declaration: 

procedure Readlnteger (var f : text; var x : integer); 

var 

value, digit : integer; 

begin 

while (f~ = ' ') and not eof(f) do 
get(f); 
value := 0; 

while (f~ in ['O'..'9']) and not eof(f) do 
begin 

digit := ordff 7 ') - ord('O'); 
value := 10*value + digit; 
get(f) 

end; 

x := value 

end; 

7.1.1 Forward-Declarations 

A procedure-declaration that has the directive forward instead of a block is called a forward 
declaration. Somewhere after the forward declaration, the procedure is actually defined by a 
deflning-declaration — a procedure-declaration that uses the same procedure-identifier, but 
omits the. formal-parameter-list, and includes a block. The forward declaration and the defining- 
declaration must be in the same procedure-and-function-declaration-part, but need not be contigu¬ 
ous; that is, other procedures or functions can be declared between them and can call the 
procedure that has been declared forward. This permits mutual recursion. 

The forward declaration and the defining-declaration constitute a complete declaration of the 
procedure. The procedure is considered to be declared at the place of the forward declaration. 


316 





Language Reference 


17 


Example of a forward declaration: 

procedure waiter(m,n : integer); 
forward; 

procedure clara(x, y : real); 

begin 

waiter(4, 5); 

end; 

procedure waiter; 
begin 

clara(8.3, 2.4); 

end; 

7.1.2 External-Declarations 

A procedure-declaration that has the directive external instead of a block is called an external 
declaration. External procedures and functions are used to declare the Pascal interface to a sepa¬ 
rately compiled or assembled routine. The external code must be linked with the rest of the 
program before execution. 

Example of an external-declaration: 

procedure Dolnits(num:integer); 
external; 

This means that Dolnits is an external procedure that will be linked with the rest of the program 
before execution. 

Note; It is the programmer’s responsibility to insure that the external procedure is 
compatible with the external declaration in the Pascal program. 

A unit (see $8.3) may declare a procedure in the interface-part and then implement this procedure 
by an external declaration. For example, 

unit a; 
interface 

procedure foo (arg:integer) ; 

implementation 

procedure f o o; 

external; 

end. 

This description of external procedures also applies to external functions. 


317 



THINK Pascal User Manual 


7.1.3 Inline-Declarations 

A procedure-declaration that has the word-symbol inline followed by one or more integer con¬ 
stants instead of a block is called an Inline declaration. Inline procedures and functions are used 
to embed machine code in a Pascal program. 

inline-body / 

---inline 



When a procedure is normally called, code is generated that reserves one or two words of function 
result (if a function is being called), and pushes the procedure’s arguments (if any). Then a JSR 
instruction is generated. By declaring a routine as inline, the compiler will cause the constants 
that follow the word-symbol inline to be generated in place of the JSR instruction. Each 
constant represents one word (16 bits) and is generated in the order given. 

Example of an inline-declaration: 

procedure trap (tos : longint); 
inline $A9ED; 

• It is the programmer’s responsibility to observe the proper rules for adjusting the stack, 
saving registers, etc. 

• An inline procedure declared in a unit’s interface section has no corresponding declara¬ 
tion in the implementation section. 

• A forward declaration or interface procedure declaration may not be later defined as an 
inline declaration. 

This description of inline procedures also applies to inline functions. 

7.2 Function-Declarations 

A function-declaration serves to declare a part of the program that computes and returns a value 
of some type. 


function-declaration 



318 










Language Reference 


17 


The function-heading specifies the identifier for the function, the formal parameters (if any), and 
the type of the function result. 

function-heading 



indefinite-string-type 


-►(string 




The syntax for a formal-parameter-list is given in §7.3. 

A function is activated by the evaluation of a function-call (see §5.2), which gives the function’s 
identifier and any actual-parameters required by the function. The function-call appears as an 
operand in an expression. The expression is evaluated by executing the function and, in effect, 
replacing the function-call with the value returned by the function. 

The statements to be executed upon activation of the function are specified by the statement-part 
of the function’s block. This block should normally contain at least one assignment-statement (see 
§6.1.1) that assigns a value to the function-identifier. The result of the function is the last value as¬ 
signed. If no such assignment-statement exists, or if it exists but is not executed, the value returned 
by the function is undefined, which is an error. 

If the function’s identifier appears as an operand in an expression within the function’s block, the 
function is executed recursively. 


319 









THINK Pascal User Manual 


Examples of function-declarations: 

function max(a : vector; n : integer) : real; 

var 

x : real; 
i : integer; 

begin 

x := a[1]; 
for i := 2 to n do 

if x < a[i ] then 
x : = a [ i ] ; 

max : = x 

end; 

function power(x : real; y : integer) : real; 

var 

w,z : real; 
i : integer; 

begin 

w : = x; 
z := 1; 
i := y; 

while i > 0 do 
begin 

{z*(w**i) = x ** y } 
if odd(i) then 
z := z*w; 
i := i div 2; 
w := sqr(w) 

end; 

{z = x**y } 
power := z 

end; 

A function can be declared forward in the same manner as a procedure (see §7.1 above). This 
permits mutual recursion. 

7.3 Parameters 

A formal-parameter-Ust may be part of a procedure-declaration or function-declaration, or it may 
be part of the declaration of a procedural or functional parameter. 

If it is part of a procedure-declaration or function-declaration, it declares the formal parameters of 
the procedure or function. Each parameter so declared is local to the procedure or function being 
declared, and can be referenced by its identifier in the block associated with the procedure or 
function. 

If it is part of the declaration of a procedural or functional parameter, it declares the formal parame¬ 
ters of the procedural or functional parameter. In this case there is no associated block and the 

320 



Language Reference 


17 


identifiers of parameters in the formal-parameter-list are not significant (see §7.3.3 and §7.3.4 
below). 

f ormal -parame t er-li s t 



pa rame t er-decl aration 


^ _ r n 

identifier—list 


KX 


parameter-type 


var 


parame ter-type 




type-identifier 


indefinite-string-type 


J 


There are four kinds of parameters: value parameters, variable parameters, procedural 
parameters, and functional parameters. They are distinguished as follows: 

• A parameter-group preceded by var is a list of variable parameters. 

• A parameter-group without a preceding var is a list of value parameters. 

• A procedure-heading or function-heading denotes a procedural or functional 
parameter; see §7.3.3 and §7.3.4 below. 

The type of a formal-parameter is denoted by either a type-identifier or the word-symbol string. 
Thus, to use a type such as array [ 0 . . 2 5 5 ] of char as the type of a parameter, you must 
declare a type-identifier for this type: 

type 

charray = array [0..255] of char; 

The identifier charray can then be used in a formal-parameter-list to denote the type. 

The interpretation of string as a parameter-type is described below. 

The univ qualifier lets you disable type-checking for a routine’s parameter. For more information 
see §7.3 7 below. 


321 








THINK Pascal User Manual 


7.3.1 Value Parameters 

For a value parameter, the corresponding actual-parameter in a procedure-statement or function- 
call (see Sections 5.2 and 6.1.2) must be an expression, and its value must not be of File-type or of 
any structured-type that contains a file-type. The formal value parameter denotes a variable local to 
the procedure or function. The current value of the expression is assigned to the formal value pa¬ 
rameter upon activation of the procedure or function. The actual-parameter must be assignment- 
compatible with the type of the formal value parameter (see §3.5.3). If the parameter-type is 
string, then the formal parameter is given a size attribute of 255. 

7.3.2 Variable Parameters 

For a variable parameter, the corresponding actual-parameter in a procedure-statement or func¬ 
tion-call (see §5.2 and §6.1.2) must be a variable-reference. The formal variable parameter denotes 
this actual variable during the entire activation of the procedure or function. 

Within the procedure or function, any reference to the formal variable parameter is a reference to 
the actual-parameter itself. The type of the actual-parameter must be identical to that of the formal 
variable parameter. However, if the parameter-type is string, then any string-type is considered 
identical to it; the size attribute of the formal parameter is always the size attribute of the actual 
parameter. 

If the reference to an actual variable parameter involves indexing an array or finding the object of a 
pointer, these actions are executed before the activation of the procedure or function. 

Components of variables of any packed structured-type cannot be used as actual variable 
parameters. 

7.3.3 Procedural Parameters 

When the formal-parameter is a procedure-heading, the corresponding actual-parameter in a pro¬ 
cedure-statement or function-call (see Sections 5.2 and 6.1.2) must be a procedure-identifier. The 
identifier in the formal procedure-heading represents the actual procedure during execution of the 
procedure or function receiving the procedural parameter. 

Example of procedural parameters: 

program PassProc; 
var 

i: integer; 

procedure a (procedure x); 
begin 

write('About to call x '); 
x 

end; 

procedure b; 
begin 

write('In procedure b') 

end; 


322 



Language Reference 


17 


function c (procedure x) : integer; 
begin 

x; 

c: =2 

end; 

begin {PassProc} 
a (b) ; 
i:= c(b) 

end. 

If the formal procedure has a formal-parameter-list, then the actual procedure’s declaration must 
also have a formal-parameter-list and both must be compatible (see §7.3.5). However, only the 
identifier of the actual procedure is written as an actual parameter; no formal or actual parameter- 
list is given. 

Example of procedural parameters with their own formal-parameter-lists: 
program test; 

procedure xAsPar(y : integer); 

begin 

writeln(*y= 1 , y) 

end; 

procedure CallProc (procedure xAgain(z:integer)); 
begin 

xAgain(1) 

end; 

begin {test} 

CallProc(xAsPar) 

end. 

If the procedural parameter, upon activation, accesses any non-local entity (by variable-reference, 
procedure-statement, function-call, or label), the entity accessed will be the one that was accessible 
to the procedure when the procedure was passed as an actual parameter. 

To see what this means, consider the following program taken from an example in the ANSI Pascal 
Standard (which is in turn taken from an early version of the Pascal Validation Suite): 

program t6p6p3p4(output); 

var 

GlobalOne, GlobalTwo : integer; 

procedure dummy; 
begin 

writeln( 1 fail4 1 ) 

end; 


323 



THINK Pascal User Manual 


procedure p(procedure £(procedure ££; procedure 99 ); 
procedure 9 ) ; 

var 

LocalToP : integer; 

procedure r; 
begin 

if GlobalOne = 1 then 
begin 

if (GlobalTwo <> 2) or (LocalToP <> 1) then 
writeln('faill') 

end 

else if GlobalOne = 2 then 
begin 

if (GlobalTwo <> 2) or (LocalToP <> 2) then 
writeln('fail2') 

else 

writeln('pass') 

end 

else 

writeln('fail3'); 

GlobalOne := GlobalOne + 1 

end; 

begin {p> 

GlobalTwo := GlobalTwo + 1; 

LocalToP := GlobalTwo; 
if GlobalTwo = 1 then 
P(f,r) 

else 

f (g,r) 

end; 

procedure q(procedure f; procedure 9 ); 
begin 

f; 

g 

end; 

begin {program} 

GlobalOne := 1; 

GlobalTwo := 0; 
p(q, dummy) 

end. 


324 




Language Reference 


17 


An explanation might make things clearer: 

1. At the call to p in the main program, GlobalOne=l and GlobalTwo=0. 

2. Within p, the formal parameter f corresponds to the actual procedure q and the formal 
g corresponds to the actual dummy. The values of Global Two and Local ToP both 
become 1. Because GlobalTwo=l, p calls itself recursively. 

3. Within this second activation of p, the formal f corresponds to the formal f of the first 
activation, which corresponds to the actual q. The formal g corresponds to the actual 
r. The values of GlobalTwo and Local ToP now become 2. Because 
GlobalTwool, this second activation of p now calls its formal parameter f, which is 
the actual procedure q. 

4. Within q, its formal parameter f corresponds to the actual procedure r and the formal 
g also corresponds to the actual r. Procedure q now calls its formals f and g, i.e. r 
and r, and the program terminates after all the activations unwind. 

It’s what happens during the two calls to procedure r within procedure q that is critical. If this 
program runs correctly, it will print ‘pass’. For this to happen, the first call to r will occur while 
GlobalOne=l and will expect LocalToP to be 1; the second call to r will occur while 
Global0ne=2 and will expect LocalToP to be 2. Since there are no assignments to LocalToP 
within r or q, how can this be? 

LocalToP is not simply local to the procedure p, it is local to each activation of p. Since there are 
two activations of p, and since r is passed as a parameter in each activation of p, each r accesses 
the variable LocalToP that is local to the activation in which it is passed. Since, in the first activa¬ 
tion of p, the value of LocalToP is 1, that is the value the first execution of r sees when it ac¬ 
cesses LocalToP. Since, in the second activation of p, the value of LocalToP is 2, that is the 
value the second execution of r sees. 

Predefined, inline, and Toolbox procedures can not be passed as procedural parameters. 

7.3.4 Functional Parameters 

When the formal parameter is a function-heading, the actual-parameter must be a function-identi¬ 
fier. The identifier in the formal function-heading represents the actual function during the 
execution of the procedure or function receiving the functional parameter. 

Functional parameters are exactly like procedural parameters, with the additional rule that 
corresponding formal and actual functions must have identical result-types. 

7.3.5 Parameter List Compatibility 

Parameter list compatibility is required of the parameter lists of corresponding formal and actual 
procedural or functional parameters. 


323 



THINK Pascal User Manual 


Two formal-parameter-lists are compatible if they contain the same number of parameters and if 
the parameters in corresponding positions match. Two parameters match if one of the following is 
true: 

• They are both value parameters of identical type. 

• They are both variable parameters of identical type. 

• They are both procedural parameters with compatible parameter lists. 

• They are both functional parameters with compatible parameter lists and result-types. 

7.3.6 Implicit parameters 

In the declaration of a method for an object-type, there is an implicit parameter called self. The 
type of self is the type of the object. Self’s scope extends over the method declaration. The 
value of self is assigned when the object variable is created. The value is a reference to the object 
whose method component was designated to activate the method. The value of self is assigned 
only when the object is created. No subsequent assignment is possible. 

7.3.7 Univ parameters 

The univ qualifier lets you disable type-checking for a routine’s parameter. When a formal param¬ 
eter’s type is qualified with univ, the actual parameter’s type does not have to be compatible with 
it, but the two types must be the same size. 

For example, this function can initialize a variable of type Point to zero, since a Point is the 
same size as a Longint: 

procedure ZeroOut (var 1: univ Longint); 
begin 

1 := 0 ; 

end; 

This initializes the point p to zero: 

ZeroOut(p); 



Language Reference 17 


7.4 Method declarations 

A method declaration describes the implementation of an object’s methods. Methods are declared 
like forward declarations of procedures and functions. The heading appears in the declaration of 
the object (see §3.2.5). The body of the method should appear in the same unit as the declaration of 
the object. 


method-declaration 



8.0 Programs and Units 

This section describes how to write the main program and how to declare units in THINK Pascal. 

8.1 Program Syntax 

A THINK Pascal program has the form of a procedure declaration except for its heading. 
program 



327 












THINK Pascal User Manual 


The occurrence of an identifier immediately after the word program declares it as the program’s 
identifier. 

The uses-clause identifies all units required by the program. 

8.2 Program-Parameters 

Only the predefined identifiers input and output are allowed as program-parameters. 

8.3 Unit Syntax 

Units provide the means to organize a Pascal program into logically related parts for modular 
construction of programs and libraries. 



unit-heading 


• H unlt 3—*C unit-identifier 


unit-i dentifier 


M identifier 


interface-part 



328 










Language Reference 


17 


implementation-part 



The identifier immediately after the word unit is the unit’s identifier. The uses-clause identifies all 
units required by the unit. 

procedure-and-function-heading-part 



The procedures and functions declared in the Interface-part must be redeclared in the imple¬ 
mentation-part. The parameters and function types of these redeclarations may be omitted, since 
they were declared in the interface-part. The procedure and function blocks for these routines are 
included in the implementation-part since they were omitted in the interface-part. 

Note; The parameters and functions types can be redeclared in the implementa¬ 
tion part only if they are identical to the declarations in the interface part. 

The scope of the declaration for an interface-part is also the implementation-part which is 
associated with that interface part. 

8.4 Uses-Clause 

The uses-clause controls which units are available to the host (other units or the main program). 
Each identifier in the identifier-list of the uses-clause is the name of a unit to be made available to 
the host. All declared entities in the used unit appear as though they are declared in the interface 
part or the main program block which contains the uses-clause. 


329 








THINK Pascal User Manual 


The uses-clause behaves differently depending on whether the “USES Extensions” option in 
Compiler Options... dialog is on or off. 

If the “USES Extensions” option is on, THINK Pascal propagates uses-clauses and lets you put uses- 
clauses in the implementation-part If the option is off, THINK Pascal treats uses-clauses as it did in 
earlier versions. 

8.5 Unit Dependencies 

In order to satisfy the requirements of §2.2.3, a unit must precede any interface-part or program that 
it supplies (see §2.2.6). It is therefore not possible to construct a valid program in which two units 
supply each other. 

If the “USES Extensions” option is off, the uses clause in the host must name all units used (directly 
or indirectly) by the host. Consider the following example: 


program Host; 
uses 
UnitA; 
begin 


unit UnitA 
interface 
uses 

UnitB 

implementation 

const 

a = b; 

end. 


unit UnitB; 
interface 
const 

b = 3; 

implementation 


The program Host uses Uni tA. UnitA uses UnitB. There is an identifier b defined as a constant 
in the interface of UnitB, but the only reference to b is in the implementation part of UnitA. In 
this case, it is not necessary to name UnitB in the uses-clause of Host. 

In the following example, Host needs to use symbols from both UnitA and UnitB, so both 
names are included in the uses-clause, even though UnitA already includes UnitB. 


program Host; 
uses 

UnitA, UnitB; 
begin 

v : = b; 


unit UnitA 
interface 
uses 
UnitB 
const 
a = b; 

implementation 

end. 


unit UnitB; 
interface 
const 

b = 3; 

implementation 


330 




Language Reference 


17 


Now consider the following example: 


program Host; 

unit UnitA; 

unit UnitB; 

uses 

interface 

interface 

UnitB, UnitA; 

uses 

const 

begin 

UnitB; 

b = 3; 

... 

const 

implementation 

end. 

a = b; 



implementation 

end. 


end 


This example is like the previous one, except that this time the reference to the identifier b is in the 
interface part of UnitA. In this case, there is an indirect reference to UnitB and it is necessary to 
name UnitB in the uses-clause of Host. Note that UnitB must be named before UnitA. 

In the first example, if the “USES Extensions” option is turned on, you can place the uses UnitB 
statement in the implementation part of UnitA because the symbol from UnitB is only used in the 

implementation of UnitA: 



program Host; 

unit UnitA 

unit UnitB; 

uses 

interface 

interface 

UnitA; 

implementation 

const 

begin 

uses 

b = 3; 

... 

UnitB 

implementation 

end. 

const 



a = b; 

end. 


end. 


If the Host needs symbols from UnitA and UnitB, and the 

“USES Extensions” option is on, you 

only need to write uses UnitA because THINK Pascal propagates the uses-clause: 

program Host; 

unit UnitA; 

unit UnitB; 

uses 

interface 

interface 

UnitA; 

uses 

const 

begin 

UnitB; 

b = 3; 

... 

const 

implementation 

end. 

a = b; 

... 


implementation 

end. 


end 


For more information and examples, see Chapter 10, “Units and Libraries. ” 

9.0 Input/Output 

This section describes the standard built-in I/O procedures and functions of THINK Pascal. 

331 



THINK Pascal User Manual 


Standard procedures and functions are predeclared Since all predeclared entities act as if they 
were declared in a “block” surrounding the program, no conflict arises from a declaration that 
redeclares the same identifier within the program. 

Note: Standard procedures and functions cannot be used as actual procedural and 
functional parameters. 

Also, the predeclared file variables input and output do not act as though they are declared in a 
block outside the program. See §9.4. 

This section and §10 use a modified BNF notation, instead of syntax diagrams, to indicate the 
syntax of actual-parameter-lists for standard procedures and functions. 

Example: 

write(f, e! [ , e 2 , e n ]) 

This represents the syntax of the actual-parameter-list of the standard procedure write, as follows: 

• f, e 1 , e 2 , and e n stand for actual-parameters. Notes on the types and interpretations 
of the parameters accompany the syntax description. 

• The notation ei, e 2 , e n means that any number of actual-parameters can 
appear here, separated by commas. 

• Square brackets [ ] indicate parts of the syntax that can be omitted. They do not 
indicate sets. 

Thus the syntax shown here means that the f parameter is required. Any number of e parameters 
may appear, with separating commas, and there must be at least one e parameter. 

9.1 Introduction to I/O 

A Pascal file variable is any variable whose type is a file-type. There are two classes of files: 
textfiles and non-textfiles. Any file variable declared to be a type identical (see §3.5.1) to the 
standard type text is a textfile and all others are non-textfiles. The standard type text is roughly 
equivalent to the type packed file of char in that a file of type text may be treated as 
though it were a packed file of char. However, the semantics of the two differ somewhat 
and, in particular, there are certain standard procedures and functions that may be applied to 
textfiles but not to files of type packed file of char. 

A file variable may (but need not) be associated with an external file. The external file may be a 
named collection of information stored on a peripheral device or, depending on the device, it may 
be the peripheral device itself. If a file variable is not associated with an external file or device, it is 
referred to as an anonymous file. 

For a file variable to be used it must be opened. An existing file may be opened with the reset 
and open procedures, and a new file may be created and opened with the rewrite and open 
procedures. Files opened with reset are read-only and files opened with rewrite are write- 
only. However, reset may be applied to a file opened with rewrite, which causes the file to 



Language Reference 


17 


become read-only. Likewise, rewrite may be applied to a file opened with reset, which causes 
the file to become write-only. 

Files opened with open are read/write files, i.e. they allow both reading and writing. Rewrite 
and reset maybe applied to files opened with open. Rewrite leaves the files as read/write 
files. Reset causes them to become read-only. 

The standard file variables input and output, if present in the program parameter list, are 
opened automatically when program execution begins and should not be opened again with 
reset or rewrite. Input is a read-only file associated with your keyboard and output is a 
write-only file associated with the text window. 

A file is a linear sequence of components, each of which has the component-type of the file. Each 
component has a component-number that is its position in the file relative to the first component 
in the file. The first component of a file is considered to be component zero. 

At any point in time, there is only one component of a file that may be accessed directly through 
the file-buffer denoted by f The current file position of f is the component number of the 
component currently accessible through f Whenever a file is opened, the current file position is 
set to component zero, i.e. to the beginning of the file. 

Under certain conditions, such as when the current file position is at the end of the file, the value of 
f ~ is said to be undefined. It is an error to attempt to use the value of f ^ when the value is 
undefined. Assignment to f * is, however, still possible. 

Note: It is an error to cause the current file position of a file f to be altered while 
a reference to the file-buffer f * exists. 

Files are normally accessed sequentially. That is, when an I/O operation is completed on a file 
component, the current file position moves to the numerically next file component Files opened 
with open, however, may also be accessed randomly with the standard procedure seek, which 
may be used to specify that the current file position is to be moved to any component number in 
the file. The function f ilepos ( f ) may be applied to any file variable f and returns the 
component number of the current file position. 

9.2 Standard Procedures and Functions for All Files 

The procedures and functions described in this section work on files of any file-type. 


333 




THINK Pascal User Manual 


9.2.1 The Reset Procedure 

Opens an existing file for sequential, read-only access or rewinds an open file, 
reset (f [, title]) 

f a variable-reference that refers to a variable of file-type. If a title is given, 

the file must not be open. Ifatitleis not given, the file must be open. 

title an optional expression with a string value. 

The string should be a valid name fora file on a file-structured device, or a 
name for a non-file-structured device. 


Reset ( f ) when f is already open causes f to be “rewound", i.e. the current file position for f 
is reset to the beginning of the file. If f was originally opened with rewrite, f becomes read¬ 
only. 

Reset (f, title) finds an existing external file with the name title, and associates f with 
this external file. It is an error if there is no existing external file with that name. 

The following conditions always hold after reset (f, [title] ) is executed: 

• Eof(f) is t rue if the file is empty. Otherwise, eof ( f ) is false. 

• The current file position is the first component of the file (component zero) and the file 
buffer variable f ~ contains the value of that component unless eof (f) is t rue, in 
which case the value of f * is undefined. 


Note: You can use the built-in function OldFileName to get the name of an 
existing text file. See §10.9.6. 

9.2.2 The Rewrite Procedure 

Creates and opens a new empty file for sequential, write-only access, or rewinds and erases an 
open file. 


rewrite(f [, title ]) 

f a variable-reference that refers to a variable of file-type. If a title is given, 

the file must not be already open. 

title an optional expression with a string value. The string should be a valid 
name for a file on a file-structured device, or a name for a non-file- 
structured device. 


Rewrite ( f ) (with no title) when f is not yet open creates an empty anonymous file for 
writing to. 

Rewrite ( f ) when f is already open causes f to be “rewound”, i.e. the current file position for 
f is reset to the beginning of the file and any prior contents of f are deleted. If f was originally 
opened with reset, f becomes write-only. 


334 



Language Reference 


17 


Re w rite(f,title) creates a new external file with the name title, and associates f with 
this external file. If an external file with the name title already exists, it is deleted and a new 
empty file with the same name is created in its place. 

The following conditions always hold after rewrite (f, [title] ) is executed: 

• Eof(f) is true. 

• The current file position is component zero, i.e. the first component written to the file 
will become the first component of the file. The value of f * is undefined. 

Note: You can use the built-in function NewFileName to prompt the user for the 
name a text file. See §10.9.7. 

9.2.3 The Open Procedure 

Opens an existing file or creates and opens a new file for random, read/write access. 
open(f, title) 

f a variable-reference that refers to a variable of file-type, f must not be 

already open. 

title an expression with a string value. The string should be a valid name for a 
file on a file-structured device, or a name for a non-file-structured device. 

Open ( f , title) opens an existing external file with the name title, and associates f with this 
external file. If an external file with the name title does not already exist, a new empty file is 
created. The file is opened for both reading and writing. 

The following conditions always hold after open (f, title) is executed: 

• Eof(f) is true if the file is empty. Otherwise, eof (f) is false. 

• The current file position is component zero and the file buffer variable f ~ contains the 
value of that component (unless eof (f) is t rue). 

9.2.4 The Close Procedure 

Closes a file. 

close (f) 

f a variable-reference that refers to a variable of file-type, f must be open 

and must not be an anonymous file. 

Close (f ) closes f, i.e. the association between f and its external file is broken and the file sys¬ 
tem marks the external file closed. All subsequent references to f are invalid (except to open it 
again). In particular, the value of f * becomes undefined. 

If a procedure or function block activation that has a file variable f local to it is exited and f is not 
already closed, f is closed automatically. If a dynamic variable created with new is, or contains, a 
file variable f that is still open when the dynamic variable is destroyed with dispose, f is closed 
automatically. If a program terminates with any file still open, the file is automatically closed. 


335 



THINK Pascal User Manual 


9.2.5 The Eof Function 

Detects the end of a file. 

eof [ (f) ] : boolean 

f a variable-reference that refers to a variable of file-type. If f is omitted, the 

function is applied to the standard file variable input. The file must be 
open. 

Returns boolean 

Eof (f) returns true if the current file position is beyond the last component of the file, or if the 
file contains no components; otherwise, eof (f) returns false. Specifically, this means the 
following: 

• After a get, eof (f) returns true if the previous file position was the last component 
of the file. 

• After a put, eof (f) returns true if the component written by the put is now the last 
file component. 

It is always an error to do a get (f) if eof (f) is true. If f is write-only, eof (f) will always 
be true. 

Note: Whenever eof (f) is true, the value of the file buffer variable f A is 
undefined. 

For some devices, eof may never be true. 

9.2.6 The Get Procedure 

Advances the current file position and reads the next component of a file, 
get(f) 

f a variable-reference that refers to a variable of file-type. The file must be 

open. 

Get (f) advances the current file position to the next file component, and assigns the value of this 
component to f *. If no next component exists, then eof (f) becomes t rue, and the value of f * 
becomes undefined. 



Language Reference 


17 


9.2.7 The Put Procedure 

Writes the file buffer to the current file position. 

put (f) 

f a variable-reference that refers to a variable of file-type. The file must be 

open and the value of f * must not be undefined. 

Put (f) writes the value of f * to f at the current file position and advances the current file posi¬ 
tion to the next file component If the new file position is beyond the end of the file, eof (f) 
becomes true, and the value of f * becomes undefined. 

If eof (f) is t rue, put (f) effectively appends the value of f * to the end of f and eof (f) 
remains true. 

9.2.8 The Seek Procedure 

Allows access to an arbitrary file component. 

seek(f, n) 

f a variable-reference that refers to a variable of file-type. The file must be 

open, and it must have been opened with open. 

n an expression with an integer-type value that specifies a file component 

number in the file. Components in files are numbered from zero. 

Seek ( f , n ) causes the file component numbered n to become the current file position. The value 
of f * becomes the value of that component unless n is greater than the number of the last compo¬ 
nent of the file, in which case eof (f ) becomes true and the value of f * is undefined. Thus, 
seek ( f, maxlongint ) always sets the current file position to the end of file. Seek of a device, 
such as P rinter : or Modem: is not allowed. 

9.2.9 The Filepos Function 

Returns the component number of the current file position, 
filepos(f) 

f a variable-reference that refers to a variable of file-type. The file must be 

open. 

Returns longint 

Filepos (f) returns a longint value that is the file component number of the current file 
position. 

9.3 Standard Procedures for Non-Textflles 

The standard procedures in this section may, in fact, be applied to textfiles. However, their 
interpretation when applied to textfiles is somewhat different and is elaborated in §9.4. 

337 



THINK Pascal User Manual 


9.3.1 The Read Procedure for Non-Textfiles 

Reads a file component into a variable. 

read(f, v x [, v 2 , v n ]) 

f a variable-reference that refers to a variable of file-type. The file must be 

open. 

v l* • • •* v n eac h v is a variable-reference with a type that the component type of f 
must be assignment-compatible with. 

If we consider f f to be the variable referenced by f, then this form of read is considered to be 
equivalent to: 

begin 

read (ff, ; 

read (ff, v 2 ); 

read (ff, v n ) 

end 

where read (f, v) is in turn equivalent to: 

begin 

v := ff"; 
get(ff) 

end 

Note: There is normally a restriction against passing components of packed vari¬ 
ables as actual variable parameters (§7.3.2). This interpretation of read means that 
each v is not considered an actual variable parameter and may be a component of 
a packed variable. 

To understand why the distinction has to be be made between f and f f above, consider the 
following example: 

var 

a: array [ 1..10 ] of file of integer; 
i, j : integer; 

i : = 1 ; 

read(a[i], i, j); 

If, say, the value of i that is read is 2, and a [i ] is reevaluated for each v, then the value read for 
i will be read from a [ 1 ] and the value of j from a [ 2 ] . In fact, a [ i ] is evaluated only once 
before anything is read, and thus all values are read from a [ 1 ] . f f is the result of this one-time 
evaluation. This f f notation will be used again in subsequent sections. 


338 



Language Reference 


17 


9.3.2 The Write Procedure for Non-Textflles 

Writes a file component from a variable. 

write (f, e 1 [, e 2 , e n ]) 

f a variable-reference that refers to a variable of file-type. The file must be 

open. 

, ..., e n each e is an expression with a type that must be assignment-compatible 
with the component type of f. 

If we consider f f to be the variable referenced by f, then this form of write is considered to be 
equivalent to: 

begin 

write(ff, e^); 
write(ff, e 2 ); 

write(ff, e n ) 

end 

where write(f, e)isin turn equivalent to: 

begin 

ff" := e; 
put(ff) 

end 

9.4 Standard Procedures and Functions for Textflles 

This section describes input and output using file variables of the standard type text. As previ¬ 
ously noted, in Pascal the type text is distinct from packed file of char. A textfile is still 
considered to be a sequence of character components (i.e. is it still a packed file of char). 
However, it is additionally considered to be a sequence of lines, where each line is terminated by 
an end-of-line character. 

All of the standard procedures and functions in §9.2 may still be applied to a textfile as though it 
were a packed file of char. However, there are additional procedures and functions you 
can use with textfiles but not other files. 

Note: When the value of the file component at the current file position of a file f 
is an end-of-line character, it appears in the file buffer f" as a space character. 

In particular, there are special forms of read and write that allow you to read and write values 
that are not of type char and will translate them to and from their character representation. For 
example, read (f, i) where i is an integer variable will read a sequence of digits (a digit be¬ 
ing one of the characters ' 0 ' through ' 9'), interpret that sequence as an integer-type value, and 
store it in i . 


339 



THINK Pascal User Manual 


As noted previously there are two standard textfile variables, input and output. The standard 
file variable input is a read-only file associated with your keyboard. If input appears in the pro¬ 
gram parameter list, then the input file is opened automatically when program execution begins 
as though a reset were performed for it The standard file variable output is a write-only file as¬ 
sociated with the Text window. If output appears in the program parameter list, then the output 
file is opened automatically when program execution begins as though a rewrite were 
performed for it. 

All of the standard procedures and functions in this section need not have a file variable explicitly 
given as a parameter (in addition to eof, as described in §9.2.5). In these cases, input or output 
will be assumed by default, depending on whether the procedure or function is input-oriented or 
output-oriented. 

9.4.1 The Read Procedure for TextfUes 

Reads one or more values from a textfile into one or more program variables, 
read( [ f, ] v x [, v 2 , ..., v n ]) 

f an optional variable-reference that refers to a variable of type text. The file 

must be open. If f is omitted, it is assumed to be the standard text file 
input. 

v l* •• •» v n each v is a variable-reference that refers to a variable of one of the 

following types: 

• Char or a subrange of char. 

• An integer-type: integer (or a subrange) or longint. 

• A real-type: real, double, extended, or computational. 

• An enumerated-type (including boolean) or a subrange. 

• A string-type. 

Read(f, v 1 , ..., v n ) is equivalent to: 

begin 

read(ff, v^); 
read(ff, v 2 ); 

read(ff, v n ) 

end 

9.4.1.1 Read with a Char-Type Variable 

This is considered equivalent to: 

begin 

v := ft"; 
get(ff) 

end 


340 




Language Reference 


17 


Remember that if the current file position is over an end-of-line character, f f * contains a space 
character. 

9.4.1.2 Read with an Integer-Type Variable 

If f is of type text and v is of an integer-type, then read (f, v) implies the reading from f of a 
sequence of characters that form a signed whole number according to the syntax of §1.4 (except 
that hexadecimal notation is not allowed). If the value read is assignment-compatible with the type 
of v, then the value is assigned to the variable v; otherwise, it is an error. 

In reading the sequence of characters, blanks and end-of-line characters preceding the first digit or 
the sign are skipped. Reading ceases as soon as a character is reached that, together with the char¬ 
acters already read, does not form part of a signed whole number, or as soon as eof (f) becomes 
true. 

It is an error if a signed whole number is not found after skipping any preceding blanks and end- 
of-line characters. 

The following things are true immediately after read (f, v) when v is of an integer-type: 

• The current file position will be over the character following the last character in the 
numeric string, unless the last character in the string was the last character in the file. 

• Eof (f) will return t rue if the last character in the numeric string was the last 
character in the file. 

• Eoln (f) will return t rue if the last character in the numeric string was the last 
character on the line. 

9.4.13 Read with a Real-Type Variable 

If f is of type text and v is of a real-type, then read (f, v) implies the reading from f of a se¬ 
quence of characters that represents a signed-number according to the syntax of §1.4 (again, except 
for hexadecimal notation). If the value read is assignment-compatible with the type of v, then the 
value is assigned to the variable v; otherwise, it is an error. 

In reading the sequence of characters, blanks and end-of-line characters preceding the first digit or 
the sign are skipped. Reading ceases as soon as a character is reached that, together with the 
characters already read, does not form a valid signed-number. 

It is an error if a valid signed-number is not found after skipping any preceding blanks and end-of- 
line characters. 

Immediately after read (f, v) , where v is a real-type variable, the following conditions are true: 

• The current file position will be over the character following the last character in the 
numeric string, unless the last character in the string was the last character in the file. 

• Eof (f) will return t rue if the last character in the numeric string was the last charac¬ 
ter in the file. 

• Eoln (f) will return t rue if the last character in the numeric string was the last 
character on the line. 


341 



THINK Pascal User Manual 


9.4.1.4 Read with a String-Type Variable 

If f is of type text and v is of a string-type, then read (f, v) implies the reading from f of a se¬ 
quence of characters up to but not including the next end-of-line character, or until the end of the 
file. The resulting character-string is assigned to the variable v. It is an error if the number of 
characters read exceeds the size attribute of v. 

Note: Read with a string variable does not skip to the next line after reading, and 
the end-of-line character is left waiting in the file buffer. For this reason, you can¬ 
not use successive read calls to read a sequence of strings, as they will never get 
past the first line — after the first read, each subsequent read will see the end- 
of-line and will read a zero-length string. Instead, use readln to read string 
values (see §9.4.2). Readln skips to the beginning of the next line after reading. 

The following things are true immediately after read (f, v) when v is of a string-type: 

• The current file position will be over the character following the last character in the 
string, unless the last character in the string was the last character in the file. 

• Eof (f) will return true if the last character in the string was the last character in the 
file. 

• Eoln (f) will return true unless eof (f) is true. 

9.4.1.5 Read with an Enumerated-Type Variable 

If f is of type text and v is of an enumerated type, then read (f, v) implies the reading from 
f of a sequence of characters that form an identifier according to the syntax of §1.2. If the identifier 
read is identical (ignoring the case of letters) to an enumerated constant of the enumerated type of 
v, the value of the enumerated constant is assigned to v; otherwise, it is an error. 

In reading the sequence of characters, blanks and end-of-line characters preceding the first letter of 
the identifier are skipped. Reading ceases as soon as a character is reached that, together with the 
characters already read, does not form part of an identifier, or as soon as eof (f) becomes true. 

It is an error if an identifier is not found after skipping any preceding blanks and end-of-line 
characters. 

If f is of type text, the following things are true immediately after read (f , v) when v is an 
enumerated-type variable: 

• The current file position will be over the character following the last character in the 
identifier, unless the last character in the string was the last character in the file. 

• Eof (f) will return t rue if the last character in the identifier was the last character in 
the file. 

• Eoln (f) will return t rue if the last character in the identifier was the last character 
on the line. 



Language Reference 


17 


9.4.2 The Readln Procedure 

The readln procedure is an extension of read for textfiles. Essentially it does the same thing as 
read, and then skips to the beginning of the next line in the input file. 

readln [ ([ f, ] [ v lf v 2 , v n ] ) ] 

f same as in read. 

v l, ..v n same as in read, except they are optional. In fact, the whole parameter list 
can be omitted. 

If the first parameter does not specify' a file variable, or if the parameter-list is omitted, the 
procedure reads from the standard file input. 

Readln (f), with no input-variables, causes the current file position to advance to the beginning 
of the next line (if there is one, else to the end of the file), i.e.: 

begin 

while not eof(ff) and not eoln(ff) do 
get(ff); 

if not eof(ff) then 
get(ff) 

end 

Readln (f, v lf ..., v n ) is equivalent to: 

begin 

read(ff ,v lf ..., v n ) ; 
readln(ff) 

end 

The following conditions are true immediately after readln (f, v), regardless of the type of v : 

• Eof (f) will return true if the line read was the last line in the file. 

• Eoln (f) will return false unless the line following the line read is empty. 


343 



THINK Pascal User Manual 


9.4.3 The Write Procedure for TextfUes 

Writes one or more values to a text file. 

write([ f, ] P 1 [, P 2 r -r P n 

f an optional variable-reference that refers to a variable of type text. The file 

must be open. If f is omitted, the procedure writes to the standard file 
output.. 

Pl» • •P n the write-parameters. Each write-parameter includes an output expres¬ 
sion, whose value is to be written to the file. As explained below, a write- 
parameter may also contain the specifications of a field-width and a number 
of decimal places. Each output expression must have a result of char-type, 
an integer-type, a real-type, a string-type, a packed-string-type, or an 
enumerated-type. At least one write-parameter must be present 

Write (f, p lf ..., p n ) is equivalent to: 

begin 

write (ff, Pi) /' 
write(ff, p n ) 

end 

9.4.3.1 Write-Parameters 

Each write-parameter has the form 

OutExpr [ : MinWidth [ : DecPlaces ] ] 

where OutExpr is an output expression. MinWidth and DecPlaces are expressions with 
integer-type values. 

MinWidth specifies the minimum field width. MinWidth must be greater than zero. Exactly 
MinWidth characters are written (using leading spaces if necessary), except when OutExpr has a 
value that must be represented in more than MinWidth characters; in this case, enough characters 
are written to represent the value of OutExpr. Likewise, if MinWidth is omitted, then enough 
characters as necessary are written to represent the value of OutExpr. 

DecPlaces specifies the number of decimal places in a fixed-point representation of a real 
value. Itcanbe specified only if OutExpr has a real-type value, and if MinWidth is also specified. 
If specified, it must be greater than zero. If DecPlaces is not specified, a floating-point 
representation is written. 

9.4.3.2 Write with a Char-Type Value 

If MinWidth is omitted, the character value of OutExpr is written on the file f. Otherwise, 
MinWidth-1 spaces followed by the character value of OutExpr is written. 


344 



Language Reference 


17 


9.43.3 Write with a String-Type Value 

Assuming the string value of OutExpr has a length L, if L<MinWidth, the string value is written 
on the file f preceded by MinWidth-L spaces. If L>MinWidth, the first MinWidth characters of 
the string are written. If L=MinWidth, or if MinWidth is omitted, the entire string value is written 
on the file. 

9.43.4 Write with an Integer-Type Value 

If OutExpr has an integer-type value, its decimal (base 10) representation is written on the file f. 
Assume that OutDigits is a string-type value that contains the decimal representation of 
abs (OutExpr) with no leading zeros unless the value of OutExpr=0, in which case 
OutDigits contains the single character ' 0 1 . If MinWidth is omitted from the write-parameter, 
then it is assumed to be zero. Thus, the representation of OutExpr is written to f as if by the 
algorithm: 

begin 

if MinWidth>=length(OutDigits)+1 then 

write(ff, 1 1 : MinWidth-length(OutDigits)-2); 

if OutExpr<0 then 
write(ff, '-') 

else if MinWidth>=length(OutDigits)+1 then 
write(ff, 1 1 ); 

write(ff, OutDigits) 

end 

9.43.5 Write with a Real-Type Value 

If OutExpr has a real-type value, its decimal representation is written on the file f. This represen¬ 
tation depends on the presence or absence of and, if present, the value of DecPlaces. 

If DecPlaces is present, a fixed-point representation is written. Assume that IntDigits is a 
string-type value that contains the decimal representation of trunc (abs (OutExpr) ) with no 
leading zeroes unless the value of OutExpr=0, in which case IntDigits contains the single 
character 'O'. Assume that FracDigits is a string-type value that contains the decimal 
representation of 

round((abs(OutExpr) - trunc(abs(OutExpr))) * io DecPlaces ) 

with enough leading zeroes to make length (FracDigits) =DecPlaces. Thus, the fixed-point 
representation is written to f as if by the algorithm: 

begin 

if MinWidth>=length(IntDigits)+length(FracDigits)+2 then 
write(ff, 1 1 : MinWidth-TotalDigits-3); 

if OutExpr<0 then 
write(ff, '-') 

else if MinWidth>=length(IntDigits)+length(FracDigits)+2 then 
write(ff, 1 '); 

write(ff, IntDigits, FracDigits) 

end 


345 



THINK Pascal User Manual 


If DecPlaces is not specified, a floating-point representation is written. If MinWidth is omitted 
from the write-parameter, then it is assumed to be 10. Assume that abs (OutExpr) has a 
representation in the floating-point notation of the form: 

m.n x 10 e 

where 0<m^9 unless OutExpr=0, in which case m=n=e=0. Assume that IntDigit is a string- 
type value that contains the decimal representation of m (a single digit). Assume that FracDigits 
is a string-type value that contains the first MinWidth-9 digits of the decimal representation of n 
rounded, and with leading zeros retained and trailing zeros added if necessary. Assume that 
ExpDigits is a string-type value that contains the decimal representation of abs (e) with enough 
leading zeros to make length (ExpDigits) =4. Also assume that NegExp has the value true if 
e<0, and otherwise the value false. 

Thus, the floating-point representation is written to f as if by the algorithm: 

begin 

if OutExpr<0 then 
write (f f, '-') 

else 

write(ff, ' '); 

write (ff, IntDigit, ' FracDigits, 'E'); 
if NegExp then 

write (ff, •-•) 

else 

write(ff, 

write(ff, ExpDigits) 

end 

9.43.6 Write with a Packed-String-Type Value 

If OutExpr is of a packed-string-type, the effect is the same as writing a string whose length is the 
number of components in the type. 

9.43.7 Write with an Enumerated-Type Value 

If the value of OutExpr is of an enumerated type, the string representation of the enumerated 
constant identifier corresponding to the value is written on the file f. If the length of this string rep¬ 
resentation is L and L<MinWidth, then MinWidth-L spaces are written out before the string. In 
any case the entire string is always written, even if L>MinWidth. 


346 



Language Reference 


17 


9.4.4 The Writeln Procedure 

The writeln procedure is an extension of write for textfiles. Essentially it does the same thing 
as write, and then writes an end-of-line character to the output file (ending the line). 

writeln [ ( [ f, ] [ p lf p 2 , p n ] ) ] 

f same as for write. 

Pi. ..p n same as for write, except they are optional. In fact, the whole parameter 
list may be omitted. 

If the first parameter does not specify a file variable, or if the parameter-list is omitted, the 
procedure writes to the standard file output. 

Writeln(f) writes an end-of-line character to the file f. 

Writeln(f, p lf ..., p n ) is equivalent to: 

begin 

write(ff, p x , p n ) ; 
writeln(ff) 

end 

The following are true immediately afterwriteln(f,v), regardless of the type of v: 

• Eof (f) will return true if the last character written became the last character in the 
file. If f is write-only, then eof (f) will necessarily be true. 

• Eoln (f) will return false unless the character following the last character written is 
an end-of-line character. 

9.4.5 The Eoln Function 

eoln [ (f) ] 

f a variable-reference that refers to a variable of type text. The file must be 

open. If f is omitted, the function is applied to the standard file input. 

Returns boolean 

Eoln (f) returns true if the character at the current file position is an end-of- line character. It is 
an error to call eoln (f) if f is a non-textfile, if f is write-only, or if eof (f) is t rue. 

Note: Every line in a file is expected to be terminated by an end-of-line character. 

This may not actually be the case. The last character in a file may not be an end- 
of-line character as it should. If a file f is read-only (opened with reset) then, 
upon reaching the end of the file, if the last character was not an end-of-line char¬ 
acter, f * becomes a space character, eoln (f) becomes true, and eof (f) re¬ 
mains false. The next attempt to read a character will then cause eof (f) Co be¬ 
come true. This will only happen if the file is read-only and not if it is read/write. 


347 



THINK Pascal User Manual 


9.4.6 The Page Procedure 

page [ (f) ] 

f a variable-reference that refers to a variable of type text. The file must be 

open. If f is omitted, the standard textfile output is assumed. 

Page (f) causes a skip to the top of a new page when f is printed or displayed. If f is write-only, 
and if the last character in f is not an end-of-line character, then one is inserted before the page is 
done. 

9.4.7 Lazy I/O 

Consider this small program: 

program count(input, output); 

var 

s : string; 

ch: char; 

begin 

write('Type a line of characters — '); 
readln(s); 

writeln('You typed length(s), ' characters'); 

end. 

If you take all the parts of this section literally, there are two problems with this program: 

• Because reset (which is done implicitly for input when the program starts) causes the first 
character of input to appear in input 7 ", the program will hang waiting for input from the 
keyboard before the write statement is executed. This means the prompt the program is 
supposed to give you for input will not appear until after you type a character. 

• Having typed a line of characters followed by the Return key (the “end-of-line key” so to speak), 
readln causes the first character of the line following the one just read to appear in input'". 
This means that the writeln following the readln will not be executed until you type 
another character following the return. 

This behavior has been the bane of Pascal programmers since the language was created. This id¬ 
iosyncrasy exists partly because Pascal was originally designed to run on batch systems — back in 
the days when interactive systems were rare. 

On batch systems, input was expected to be associated with a previously prepared input file 
(typically a deck of punched cards) and output was expected to be associated with a file where 
the results of your program would appear for your inspection after its execution was complete 
(typically a line printer listing). 

Although, when the ANSI Pascal Standard was being drafted, many subtle changes were made to 
the Pascal language, this problem was never completely resolved. So many programs had already 
been written that depended on this behavior when doing I/O. To change the language in any sig- 

348 



Language Reference 17 


nificant way would have made these programs invalid. Instead, the standard is worded in such a 
way that it is possible to get around this problem. 

For instance, when the standard specifies that, after reset (f) , f * contains the first component 
of the file, it does so in a way that allows f* to remain undefined until its value is needed. Thus, in 
the above program, it’s not strictly necessary to read the first character from the keyboard as soon 
as execution begins; it suffices to do so when the readln needs that character. Likewise, after 
readln processes the end-of-line character (the Return key), it is not necessary to then read an¬ 
other character from the keyboard. It is in fact never necessary because the program does not 
reference input again. 

Interpreting the standard’s semantics in this way is popularly known as Lazy I/O, and is the only 
technique that allows interactive I/O in Pascal while preserving the standard’s I/O semantics. Other 
techniques exist, but they cause I/O operations to behave differently depending on whether you 
have specified that the I/O is to be done interactively or not. These other techniques make it diffi¬ 
cult to write a program that runs the same when its input comes from a file as it does when input 
comes from a keyboard. 

The Lazy I/O technique involves separating the operations of advancing the current file position 
and doing input from the file by deferring the actual input of data from a file until absolutely 
necessary. Conditions that make input from a file f necessary include: 

• A reference to f A other than to assign it a value or to pass it as an actual variable 
parameter. 

• A call to eof (f) . In this case, input may be necessary because it is not (necessarily) 
possible to know whether the end of the file has been reached without trying to read 
beyond it. 

• A call to eoln (f) . In this case, input may be necessary to get another character and 
see if it is an end-of-line character. 

• A call to get (f) . In this case, input will only be necessary if prior to the call to get 
there was deferred input that was never actually done. If so, the original deferred input 
will be performed, but the input implied by the get will in turn be deferred. 

• A call to read or readln from f. Here, the input necessary to do the read or readln 
will be performed, but the input of the component following the last component read 
will be deferred. 


349 




THINK Pascal User Manual 


Although Lazy I/O makes it possible to write interactive programs without much difficulty, you 
should nevertheless be aware of the conditions described above to avoid peculiar situations that 
may cause your program to hang waiting for input unexpectedly. For instance: 

program process_lines(input, output); 

var 

s : string; 

begin 

repeat 

write(* > *) ; 
readln(s); 

until eoln 

end. 

This program might be intended to read and process lines, prompting each line with the * >' char¬ 
acter, until an empty line is entered. An empty line is an end-of-line character immediately follow¬ 
ing the end of the previous line. The program reads a line and tests to see if an end-of-line immedi¬ 
ately follows. The problem is that the program, after prompting for and reading the first line, will 
stop as a result of the eoln and wait for another character to be typed before issuing another 
prompt. 

A better way to write this program, one that avoids this problem, might be: 

program process_lines(input, output); 

var 

s: string; 
empty : boolean; 

begin 

empty := false; 
repeat 

write('>'); 
if eoln then 

empty := true 

else 

begin 

readln(s); 


end 

until empty 

end. 


350 



Language Reference 


17 


or even better: 

program process_lines(input, output); 

var 

s : string; 

begin 

repeat 

write('>'); 
readln(s); 

until length(s) = 0 

end. 

9.5 Devices on the Macintosh 

On the Macintosh, there are basically three devices to be concerned about: disk drives, a printer, 
and a modem. 

The disk drives are never addressed directly. Rather, you address the disks themselves by name. 
Each disk is referred to as a volume and the disk’s name is its volume name. For disk files, the 
title parameter for reset, rewrite, and open (see §§9.2.1 through 9.2.3) consists of a file 
name optionally preceded by a volume name and a colon, e.g.: 

MyVolume:MyFile 

To learn more about volumes and files, see Inside Macintosh II, Chapter 4, “The File Manager”,” 
Inside Macintosh IV, Chapter 19, “The File Manager,” and Inside Macintosh VI, Chapter 25, “The 
File Manager.” 

For the printer and modem, the title parameter for reset, rewrite, and open consists of the 
device name followed by a colon: 

Printer: 

Modem: 

The device name for the printer is simply printer:. Likewise the device name for the modem is 
modem:. Since the printer is a write-only device, you can only use * printer: ' as the title 
parameter for rewrite. It is an error to give * printer: * as the title parameter for reset or 
open. 

The device names printer:: and modem: are provided for convenience only. In most cases, using 
these device names is not sufficient for general applications, and completely inadequate for 
Macintosh application. Please see Inside Macintosh to learn more about the Serial Manager and the 
Print Manager. 

• A file variable opened with * modem: 1 as the title parameter reads from and writes to the 
modem at 300 baud 


351 



THINK Pascal User Manual 


• It is an error to open a file variable with ‘printer: ' or 'modem: * as the title parameter if it 
is not of type text. 

• For the printer and the modem to work properly, they must be connected to their proper 
sockets in the back of the Macintosh. See the Macintosh user’s guides for details. 

9.6 Error Handling Routines 

Most of the time, THINK Pascal reports I/O errors with a dialog box. When the dialog box appears, 
it doesn’t give you an opportunity to handle the error in your program. The routines described in 
this section, let you turn off THINK Pascal’s I/O error checking so you can do it yourself. 

9.6.1 IOCheck 

Enables and disables runtime checking of I/O errors. 

IOCheck(bool) 

Bool a boolean value. If bool is true, THINK Pascal reports dynamic errors. If 

bool is false, you can check the results of input/output operations with 
the IOResult function. 


9.6.2 IOResult 

Returns result of last of I/O routine. 

IOResult 

Returns integer 

IOResult returns the result of the last I/O operation. If the value is negative, it is a Macintosh error. 
The meanings of positive values are: 

0 no error 

15 can’t close an anonymous file 

16 file is not opened for writing 

17 file is not opened for reading 

18 file is not opened for random access 

19 end of file during read 
2 0 file is not open 

21 file is not a disk file 

22 component in seek is < 0 
2 3 file is already open 

2 4 bad device type for open, rewrite, or reset 
2 5 port is in use by AppleTalk 
2 6 illegal signed number in read 
2 7 string too long in read or write 
2 8 illegal enum value in read 
2 9 illegal floating point value in read 


352 



Language Reference 17 


10.0 Standard Procedures and Functions 

This section describes all the standard (built-in) procedures and functions in THINK Pascal, except 
for the I/O procedures and functions described in §9, and the Macintosh Toolbox procedures and 
functions described in Inside Macintosh. 

Standard procedures and functions are predeclared. Since all predeclared entities act as if they 
were declared in a block surrounding the program, no conflict arises from a declaration that 
redeclares the same identifier within the program. 

Note: You cannot use standard procedures and functions as actual procedural and 
functional parameters. 

This section uses a modified BNF notation, instead of syntax diagrams, to indicate the syntax of ac¬ 
tual-parameter-lists for standard procedures and functions. The notation is explained at the 
beginning of §9. 

10.1 Dynamic Allocation Procedures 

The procedure new creates dynamic variables that your program uses. Dynamic variables are vari¬ 
ables that can be accessed only through pointer variables, and they are created by allocating a re¬ 
gion of memory from a portion of free memory called the heap. The address of the allocated re¬ 
gion is the pointer value that is used to access the dynamic variable. The dispose procedure is 
used to destroy dynamic variables created with new, in the process returning that variable’s region 
of memory to the heap for reuse. 

10.1.1 The New Procedure 

Creates a new dynamic variable and sets a pointer variable to point to it, or creates a new object 
and sets a reference variable to reference it. 

new (p [, c lf c 2 , ...f c n ]) 

p a variable-reference that refers to a variable of any pointer-type. This is a 

variable parameter. 

c 1 , ..., c n each c (if given) is a constant. If the base-type of p is a record-type with 

variants, then each c may be a constant corresponding to a case-constant of 
a variant of a variant-part (see below). Variants are not allowed for reference 
variables. THINK Pascal always allocates enough space for the largest 
variant regardless of the case-constants supplied. 

Or 

p a variable-reference that refers to a variable of reference-type. 

New (p) creates a new variable of the base-type of p, and makes p point to it. The variable can be 
referenced as p''. It is an error if the heap does not contain enough free space to create the new 
variable. 

353 



THINK Pascal User Manual 


If the base-type of p is a record-type with a variant-part, new (p) allocates enough memory to the 
variable to accommodate the largest variant. If p is a reference variable, new creates an object 
whose type corresponds to p’s reference type and sets p to reference it. 

Keep in mind that THINK Pascal always allocates enough memory for the largest case variant. For 
compatibility with other versions of Pascal, THINK Pascal lets you supply a constant c that is a 
case-constant of one of the variants of the variant-part. If the record variant itself contains a variant- 
part, then a case-constant c may be given to select a particular variant of that variant-part, and so 
on. Each c in the parameter list must be given in the order of the nesting of the variants, one for 
each level of nesting. In some versions of Pascal, only the amount of memory necessary to 
accommodate that particular variant is allocated to the variable. 

10.1.2 The Dispose Procedure 

Destroys a dynamic variable or reference variable. 

dispose (p [, c lf c 2 , c n ]) 

P a variable-reference that refers to a pointer-variable. It must be a pointer that 

was previously assigned by the new procedure or was assigned a meaning¬ 
ful value by an assignment statement. It is an error to attempt to dispose 
of a pointer variable that is currently being accessed, or whose value is 
undefined or is nil. 

ci, ..., c n Each c (if given) is a constant. If the base-type of p is a record-type with 

variants, then each c may be a constant corresponding to a case-constant of 
a variant of a variant-part (see 10.1.1 above). 

Or: 

P a variable reference that refers to a variable of reference-type. 

Dispose (p) destroys the variable referenced by p and returns its memory region to the heap. 

The value of p then becomes undefined and it is an error to subsequently make reference to p^. 

If the dynamic variable pointed to by p was created by new with a list of case-constants, then the 
same list of case-constants (in the same order) must be given to dispose. 


354 



Language Reference 


17 


10.1.3 HeapCheck Procedure 

Enables and disables runtime checking of dynamic memory errors. 

HeapCheck(bool) 

Bool a boolean value. If bool is true, THINK Pascal reports dynamic errors. If 

bool is false, you can check the results of dynamic memory allocations 
with the HeapResult function. 

10.1.4 HeapResult Function 

Returns result of the last of dynamic memory allocation routine. 

HeapResult 

Returns integer 

HeapResult returns the result of the last heap operation. If the value is negative, it is a Macintosh 
error. The meanings of positive values are: 

0 no error 

11 attempt to DISPOSE a nil pointer 

10.2 Transfer Procedures and Functions 

10.2.1 The Trunc Function 

Converts a real-type value to a longint value. 

trunc(x) 

x an expression with a value of a real-type. 

Returns longint 

Trunc (x) returns a longint result that is the value of x rounded to the nearest whole number 
that is between 0 and x inclusive. It is an error if the result of this rounding is outside the range 
-maxlongint-1..maxlongint. 

10.2.2 The Round Function 

Converts a real-type value to a longint value. 

round(x) 

x an expression with a value of a real-type. 

Returns longint 

Round (x) returns a longint result that is the value of x rounded to the nearest whole number. If 
x is exactly halfway between two whole numbers, the result is the whole number with the greatest 
absolute magnitude. It is an error if the result of this rounding is outside the range 
-maxlongint..maxlongint. 


355 



THINK Pascal User Manual 


10.2.3 The Ord4 Function 

Converts an ordinal-type or pointer-type value to a longint value. 
ord4 (x) 

x an expression with a value of ordinal-type or pointer-type. 

Returns longint 

0rd4 (x) returns the ordinal value of x. 

If x is of a pointer-type, the result is the address of the dynamic variable pointed to by x. 

If x is of an ordinal-type, the result is the ordinality of x (see §3.1.1), represented as a longint. 

10.2.4 The Pointer Function 

Converts an integer-type value to a generic pointer-type value, 
pointer(x) 

x an expression with a value of integer-type. 

Returns a generic pointer which matches any pointer 

Pointer (x) returns a pointer value that points to whatever is at the address x as though it were a 
dynamic variable created at that address. This pointer is of the same type as nil in that it is 
assignment-compatible with any pointer-type. 

As a convenience, pointer may be also applied to an expression of any pointer-type, effectively 
making that expression assignment-compatible with any (other) pointer-type. 

10.3 Arithmetic Functions 

In general, any extended real-type result returned by an arithmetic function is an approximation. 
There is one exception to this: the result of the abs function is exact 

10.3.1 The Odd Function 

Tests whether an integer-type value is odd. 

odd(x) 

x an expression with a value of integer-type. 

Returns boolean 

Odd (x) returns true if x is odd, i.e. not divisible by 2 without a remainder. If x is even it returns 
false. 


356 



Language Reference 


17 


10.3.2 The Abs Function 

Returns the absolute value of a numeric value. 

abs(x) 

x an expression with a value of an integer-type or a real-type. 

Returns integer, longint, or extended. 

Abs (x) returns the absolute value of x; i.e. if x is negative, -x is returned; otherwise x is returned. 
If x is of a real-type, the result type is extended. If x is of type longint, the result type is 
longint. Otherwise, the result type is integer. 

10.3.3 The Sqr Function 

Returns the square of a numeric value. 

sqr(x) 

x an expression with a value of an integer-type or a real-type. 

Returns integer, longint, or extended. 

Sqr (x) returns the square of x, i.e. x*x. 

It is an error if the result is not within the range of values representable by the result-type (see §3.1). 

10.3.4 The Sqrt Function 

Returns the square root of a numeric value. 

sqrt(x) 

x an expression with a value of an integer-type or real-type. It is an error if 

x<0. 

Returns extended. 

Sqrt (x) returns the positive square root of x, i.e. the positive value y such that y*y=x. It is an 
error if the result is a value too small to be represented by the real-type extended (see §3.1.2). 


337 



THINK Pascal User Manual 


10.3.5 The Sin Function 

Returns the sine of a numeric value. 

sin (x) 

x an expression with a value of an integer-type or real-type. This value is 

assumed to represent an angle in radians. 

Returns extended. 

Sin (x) returns the trigonometric sine of x. 

10.3.6 The Cos Function 

Returns the cosine of a numeric value. 

cos(x) 

x an expression with a value of an integer-type or real-type. This value is 

assumed to represent an angle in radians. 

Returns extended. 

Cos (x) returns the trigonometric cosine of x. 

10.3.7 The Exp Function 

Returns the exponential of a numeric value. 

exp(x) 

x an expression with a value of an integer-type or real-type. 

Returns extended. 

Exp (x) returns the value of e x , where e is the base of the natural logarithms. It is an error if the 
result cannot be represented with the real-type extended (see §3.1.2). 

10.3.8 The Ln Function 

Returns the natural logarithm of a numeric value. 

In (x) 

x an expression with a value of an integer-type or real-type. It is an error if 

x£0. 

Returns extended. 

Ln (x) returns the natural logarithm 0og e ) of x. 


358 



Language Reference 17 


10.3.9 The Arctan Function 

Returns the arctangent of a numeric value. 

arctan(x) 

x an expression with a value of an integer-type or real-type. It is an error if 

x<0. 

Returns extended. 

Arctan (x) returns the principal value, in radians, of the arctangent of x. 

10.4 Ordinal Functions 

10.4.1 The Ord Function 

Returns the ordinal number of an ordinal-type or pointer-type value, 
o rd (x) 

x an expression with a value of ordinal-type or pointer-type. 

Returns integer or longint 

If x is of pointer-type, the result is the longint address of the dynamic variable pointed to by x. 

If x is of an ordinal-type, the result type is the ordinality of x (see §3.1.1). If x is of type longint, 
the result type is longint. Otherwise, the result type is integer. 

10.4.2 The Chr Function 

Returns the char value corresponding to a whole-number value, 
chr(x) 

x an expression with an integer-type value that must be in the range 0..255. 

Returns C har 

Chr (x) returns the char value whose ordinal number is x. 

For any char value ch, the following is always true: 
chr(ord(ch)) = ch 


339 



THINK Pascal User Manual 


10.4.3 The Succ Function 

Returns the successor of a value of ordinal-type. 

succ(x) 

x an expression with a value of ordinal-type. 

Returns same as parameter. 

Succ (x) returns the successor of x. 

It is an error if x is the last value in the type of x, i.e. it has no successor. Otherwise 
ord(succ(x))=ord(x)+1 

10.4.4 The Pred Function 

Returns the predecessor of a value of ordinal-type. 

pred(x) 

x an expression with a value of ordinal-type. 

Returns same as parameter. 

P red (x) returns the predecessor of x. 

It is an error if x is the first value in the type of x, i.e. it has no predecessor. Otherwise, 
ord(pred(x))=ord(x)-1 

10.5 String Procedures and Functions 

10.5.1 The Length Function 

Returns the current length of a value of string-type. 

length(str) 

s t r an expression with a value of a string-type. 

Returns integer 

Length (str) returns the current length attribute of str (see §3.3). 


360 




Language Reference 17 


10.5.2 The Pos Function 

Searches a string for the first occurrence of a specified substring, 
pos(substr, str) 

substr an expression with a value of a string-type, 

str an expression with a value of a string-type. 

Returns integer 

Pos (substr, str) searches for substr within str, and returns an integer value that is the 
index of the first character of substr within str. 

If substr is not found, pos (substr, str) returns zero. 

10.5.3 The Concat Function 

Takes a sequence of strings and concatenates them. 

concat (s x [, s 2 , ... s n ]) 

s l* •••< s n eac h is an expression with a value of string-type. Any practical number of 
parameters may be passed. 

Returns string-type 

Concat ( s 1 , ..., s n ) concatenates all the parameters in the order in which they are written, and 
returns the concatenated string. Note that the number of characters in the result cannot exceed 255. 

10.5.4 The Copy Function 

Returns a substring of specified length, taken from a specified position within a string, 
copy(source, index, count) 

source an expression with a value of a string-type, 

index an expression with an integer-type value, 

count an expression with an integer-type value. 

Returns string-type 

Copy (source, index, count) returns a string containing count characters from source, 
beginning at source [index] . If count<0, then a null string is returned. If indexCl or 
index+count>length (source) , i.e. if character positions outside the range 
1. . length (source) are implicitly referenced, it is not an error. However, only the characters 
that lie within that range are copied. 


361 



THINK Pascal User Manual 


10.5.5 The Delete Procedure 

Deletes a substring of specified length from a specified position within the value of a string 
variable. 

delete(dest, index, count) 

dest a variable-reference that refers to a variable of a string-type. This is a 

variable parameter. 

index an expression with an integer-type value. 

count an expression with an integer-type value. 

Delete (dest, index, count) removes count characters from the value of dest, begin¬ 
ning at dest [index] . If indexCl or index+count>length (source), i.e. if character posi¬ 
tions outside the range are implicitly referenced, it is not an error. However, only the characters 
that lie within that range are deleted. 

10.5.6 The Omit Function 

Deletes a substring of specified length from a specified position within a string value and returns 
the result. 

omit(str, index, count) 

s t r a value of string-type. 

index an expression with an integer-type value. 

count an expression with an integer-type value. 

Returns string-type 

Omit (str, index, count) removes count characters from the value of str, beginning at 
dest [index] , and returns the resulting string value. This is similar to delete except that str is 
not affected; the resulting string value is returned as the value of the function instead. 


362 



Language Reference 


17 


10.5.7 The Insert Procedure 

Inserts a substring into the value of a string variable, at a specified position, 
insert(source, dest, index) 

source an expression with a value of string-type. 

dest a variable-reference that refers to a variable of string-type. This is a variable 

parameter. 

index an expression with an integer-type value. 

Insert (source, dest, index) inserts source into dest. The first character of source 
becomes dest [index]. If indexCl or index>length (dest), it is not an error. If indexCl 
then source is appended to the left of dest. Ifindex>length (dest) then source is ap¬ 
pended to the right of dest. It is an error, however, if the length of the resulting string is greater 
than 255. 

10.5.8 The Include Function 

Inserts a substring into a string value, at a specified position, and returns the result, 
include(source, str, index) 


source 

an expression with a value of string-type. 

str 

a value of string-type. 

index 

an expression with an integer-type value. 

Returns 

string-type 


Include (source, str, index) inserts source into the value of str at str [index] and 
returns the result. This is similar to insert except that str is not affected; the resulting string 
value is returned as the value of the function instead. 

10.6 THINK Pascal Window Manipulation Procedures 

10.6.1 The HldeAll Procedure 

HideAll 

Hide All causes all of the windows on the THINK Pascal desktop to be hidden. All of these win¬ 
dows may be revealed again with the Windows menu. In addition, the Text and Drawing 
windows may be revealed by calling the procedures described below. 

10.6.2 The ShowText Procedure 

ShowText 

ShowText causes the Text window to be revealed and to become the active window. The size and 
position of the window is unchanged. 

363 



THINK Pascal User Manual 


10.6.3 The ShowDrawing Procedure 

ShowDrawing 

ShowDrawing causes the Drawing window to be revealed and to become the active window. The 
size and position of the window is unchanged. 

10.6.4 The SetTextRect Procedure 

SetTextRect(WRect) 

WRect a value of type Rect. 

WRect is a rectangle in QuickDraw’s global coordinate system that determines the position and 
size of the Text window on the Macintosh screen. 

10.6.5 The SetDrawingRect Procedure 

SetDrawingRect(WRect) 

WRect a value of type Rect. 

WRect is a rectangle in QuickDraw’s global coordinate system that determines the position and 
size of the Drawing window on the Macintosh screen. 

10.6.6 The GetTextRect Procedure 

GetTextRect(WRect) 

WRect a value of type Rect. 

GetTextRect returns a rectangle in WRect with coordinates in QuickDraw’s global coordinate 
system. This rectangle indicates the current size and position of the Text window. 

10.6.7 The GetDrawingRect Procedure 

GetDrawingRect(WRect) 

WRect a value of type Rect. 

GetDrawingRect returns a rectangle in WindowRect with coordinates in QuickDraw’s global 
coordinate system. This rectangle indicates the current size and position of the Drawing window. 

10.6.8 The SaveDrawing Procedure 

SaveDrawing(title) 

title a string-type value that must contain a valid file name for a file-structured 
device (see §9.5). 

SaveDrawing saves the contents of the Drawing window as a file that may be read by MacPaint. 
The title string contains the name of the picture file to be created. If a file by that name already 
exists, it is overwritten. 


364 


Note: SaveDrawing actually saves the contents of the current QuickDraw 
GrafPort. However, unless you specifically change the current port to be another 



Language Reference 


17 


port, the current port will always be the Drawing window’s GrafPort when your 
program is running. 

10.7 Bit operations 

These procedures and functions in this section operate on the bits of values. These functions and 
procedures actually generate inline code. 

10.7.1 BitAnd 

BitAnd(Nl t N2) 

Nl, N2 either integer or longint values. 

Returns integer or longint 

BitAnd returns Nl AND N2. If both of the arguments to BitAnd are integer, the result is 
integer. If one or both of the arguments is a longint, the result is a longint. 

10.7.2 BitOr 

BitOr(Nl r N2) 

Nl, N2 either integer or longint values. 

Returns integer or longint 

BitOr returns Nl OR N2. If both of the arguments to BitOr are integer, the result is integer. If 
one or both of the arguments is a longint, the result is a longint. 

10.7.3 BitXor 

BitXor(Nl r N2) 

Nl, N2 either integer or longint values. 

Returns integer or longint 

BitXor returns Nl XOR N2. If both of the arguments to BitXor are integer, the result is 
integer. If one or both of the arguments is a longint, the result is a longint. 

10.7.4 BitNot 

BitNot (aNum) 

aNum either an integer or longint value. 

Returns integer or longint 

BitAnd returns the one’s complement of aNum, that is, all the bits are inverted. If the argument to 
BitNot is integer, the result is integer. If the argument is a longint, the result is a 
longint. 


365 



THINK Pascal User Manual 


10.7.5 BAND 

BAND (x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended 

Returns longint 

BAND returns x AND y. 

10.7.6 BOR 

BOR(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BOR returns x OR y. 

10.7.7 BXOR 

BXOR(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BXOR returns x XOR y. 

10.7.8 BNOT 

BNOT(x) 

x a scalar value of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BNOT returns NOT x, that is the one’s complement of x. 

10.7.9 BSL 

BSL(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BSL returns x left-shifted by y bits. 


366 



Language Reference 


17 


10.7.10 BSR 

BSR(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended 

Returns longint 

BSR returns x right-shifted by y bits. 

10.7.11 BROTL 

BROTL(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BROTL returns x left-rotated by y bits. The high order bits rotate the low order bits. 

10.7.12 BROTR 

BROTR(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns longint 

BROTR returns x right-rotated by y bits. The low order bits rotate to the high order bits. 

10.7.13 BTST 

BTST(x, y) 

x, y scalar values of any size. Values smaller than 32 bits are zero extended. 

Returns boolean 

BTST returns t rue if bit y in x is set. The high order bit is bit 31; the low order bit is bit 0. 

10.7.14 BCLR 

BCLR(x, y) 

x a var longint variable reference 

y an integer reduced modulo 32. 

BCLR clears bit y of x. 


367 



THINK Pascal User Manual 


10.7.15 BSET 

BSET (x,y) 

x a var longint variable reference 

y an integer reduced modulo 32. 

BSET sets bit y of x. 

10.7.16 HlWord 

HiWord(long) 

long a longint value. 

Returns integer 

HiWord returns the upper l6-bits of a longint value as an integer value. 

10.7.17 HlWrd 

HiWrd(long) 

long a longint value. 

Returns integer 

HiWrd returns the upper l6-bits of a longint value as an integer value. 

10.7.18 LoWord 

LoWord(long) 

long a longint value. 

Returns integer 

LoWord returns the lower l6-bits of a longint value as an integer value. 

10.7.19 LoWrd 

LoWrd(long) 

long a longint value. 

Returns integer 

LoWrd returns the lower l6-bits of a longint value as an integer value. 

10.8 Control Procedures 

These procedures let you exit loops and routines. 

368 



Language Reference 17 


10.8.1 Cycle 

Cycle to next repetition of enclosing loop statements. 

Cycle 

Cycle goes to the next repetition of the enclosing while, repeat, or for statement. It can only 
be used within one of these statements, 

10.8.2 Leave 

Leave enclosing loop statements. 

Leave 

Leave goes to the statement following the enclosing while, repeat, or for statement. It can 
only be used within one of these statements, 

10.8.3 Exit 

Exit enclosing procedure. 

Exit(procName) 

procName the name of an enclosing procedure. 

Exit returns from the procedure procName. ProcName must be the name of the procedure in 
which the statement appears, or it must nest the procedure in which it appears. 

10.8.4 Halt 

Exit the program 

Halt 

Halt exits the program. 

10.9 Miscellaneous Procedures and Functions 

10.9.1 The Sizeof Function 

Returns the number of bytes occupied by a specified variable, or by any variable of a specified 
type. 


sizeof(id) 

id either a variable-identifier ora type-identifier 

Returns integer or longint 

Sizeof (id) returns the number of bytes of memory occupied by id. If id is a variable-identifier; 
if id is a type-identifier, it returns the number of bytes occupied by any variable of type id. If the 
size fits in an integer, sizeof returns an integer; otherwise, it returns a longint. 

369 



THINK Pascal User Manual 


10.9.3 The WriteDraw Procedure 

WriteDraw is similar to write, except that the text output goes to the current Graf Port at the 
current PenLoc instead of to a text file or to the Text window. 

WriteDraw (p! [, P 2' •••' Pn ^ 

Pl.p n the write-parameters. Each write-parameter includes an output expres¬ 

sion, whose value is to be written to the file. As explained in §9.4.3.1, a 
write-parameter may also contain the specifications of a field-width and a 
number of decimal places. Each output expression must have a result of 
char-type, an integer-type, a real-type, a string-type, a packed-string-type, 
or an enumerated-type. At least one write-parameter must be present. 

WriteDraw takes the same parameter list as write (see §9.4.3), except that no file parameter is 
ever given. The text that results from the evaluation of each write-parameter is written in the 
current Graf Port starting at the current pen position. 

Do not forget to set current PenLoc before using WriteDraw. 

10.9.4 The StringOf Function 

StringOf is also similar to write, except that the text output is returned as a string-type value 
instead of being written to a textfile or to the Text window. 

StringOf (Pi [/ P 2 ' •••' Pn D 

Pi* • • •» Pn the write-parameters. Each write-parameter includes an output expres¬ 
sion, whose value is to be written to the file. As explained in §9.4.3.1, a 
write-parameter may also contain the specifications of a field-width and a 
number of decimal places. Each output expression must have a result of 
char-type, an integer-type, a real-type, a string-type, a packed-string-type, 
or an enumerated-type. At least one write-parameter must be present. 

Returns string-type 

StringOf takes the same parameter list as write (see §9.4.3), except that no file parameter is 
ever given. The text that results from the evaluation of each write-parameter is accumulated as a 
string-type value that is the result of the function call. 


370 




Language Reference 17 


10.9.5 The Readstring Procedure 

Readstring is similar to read, except that the text is read from a string parameter instead of a 
textfile. 

Readstring(s, v x [, v 2 , v n ]) 
s a string-type value 

v l» • •v n Each v is a variable-reference that refers to a variable of one of the following 
types: 

• Char or a subrange of char. 

• An integer-type: integer (or a subrange) or 1 ongint. 

• A real-type: real, double, extended, or computational. 

• An enumerated-type (including boolean) or a subrange . 

• A string-type. 

Readst ring reads text from the string value s just as if it were doing a read (see §9.4.1) from a 
textfile. The values read are placed in the v parameters in the given order. Just as it is an error to at¬ 
tempt to read beyond the end of a file, it is an error to attempt to read characters beyond the end of 
the string value s. 

10.9.6 The OldFileName Function 

Returns the title of an existing disk file selected by the user. 

OldFileName(Prompt) 

p r ompt a string-type value. 

Returns string-type 

OldFileName causes a dialog box to appear on the Macintosh screen. The Prompt string is not 
displayed. It is there for historical reasons, but must be supplied. With the dialog box, the user can 
peruse the existing files on any number of disks and select one of them. OldFileName returns a 
string value that is the title of the file the user selected, which can in turn be given to reset, 
rewrite, or open. 


371 



THINK Pascal User Manual 


10.9.7 The NewFileName Function 

Returns the title of a new disk file selected by the user. 

NewFileName(Prompt [, Name ]) 

P rompt a string-type value 

Name an optional string-type value. 

Returns string-type 

NewFileName causes a dialog box to appear on the Macintosh screen. The Prompt string is dis¬ 
played within this box to give the user some indication of what the box is asking for. With the dia¬ 
log box, the user can select any disk and enter the name (or choose the default name) of a file to 
be created on that disk. NewFileName returns a string value that is the title of the file the user 
selected, which can in turn be given to reset, rewrite, or open. 

The Name string is displayed in the dialog box as selected text, and will be the string returned 
unless the user enters another name. 

10.9.8 The Synch Procedure 

Synch 

The Synch procedure is used to synchronize your program’s actions with the Macintosh screen’s 
drawing cycle, which occurs every 60 th of a second. This may, in particular, be used to synchronize 
calls to QuickDraw with the screen drawing cycle to avoid unnecessary flicker and scanning bar 
phenomena when moving things around quickly in the Drawing window. 

When you call the synch procedure, the procedure will not return until the screen has reached the 
point in its cycle where the electron beam has returned to the top of the screen and is about to re¬ 
draw the entire picture. Depending on where your QuickDraw calls are going to be drawing on the 
screen, additional delays may be necessary to synchronize the drawing with the timing of the 
electron beam’s scanning of the screen. 

10.9.9 The Note Procedure 

Note(Freq, Ampl, Duration) 

Freq The frequency, an longint value in the range 12 . .783360 

Ampl The amplitude, an integer-type value in the range 0. .255 

Duration The duration, an integer-type value in the range 0..255. 

Note causes a single square-wave tone to be generated, of the given amplitude, duration, and 
frequency (the frequency is specified in hertz). 


372 



Language Reference 17 


10.9.10 The Inline Procedures 

InlineP (Trap [, p lf p 2 , ..., p n ]) 

BlnlineF (Trap [, p lf p 2 , ..., p n ]) 

WInlineF (Trap [, p lr p 2 , p n ]) 

LInlineF (Trap [, p lr p 2 , ..., p n ]) 

T rap an expression with an integer value that indicates the number of the trap to 

be called 

Pi 1 •» P n each p (if given) is an expression with any type value. 

The InLine procedures provides the ability to call the stack-based Macintosh Toolbox routines. 

The InLine procedures work by disabling all type and parameter checking normally used in THINK 
Pascal. This makes it possible for just four predefined routines to invoke any stack-based Toolbox 
trap. 

Toolbox routines can be either functions or procedures. Functions can return either a byte (8-bits), 
a word (l6-bits), or a longword 32-bits as results. 

Invoke Toolbox routines with one of the three following routines: 

This routine Invokes these Toolbox routines 

BinlineF Toolbox functions which return a byte (boolean) 

WInlineF Toolbox functions which return a word (integer) 

LInlineF Toolbox functions which return a longword (longint) 

InlineP Toolbox procedures 

All procedures and functions use the same basic parameter-passing mechanism. Parameters are 
passed either by reference (variable parameters) or by value. To force a parameter to an InLine 
routine to be passed by reference, the @ operator may be applied to the name of the variable that is 
to be passed. For example, 

GWindPtr 

will force a reference to WindPtr to be passed to a Toolbox routine. Simply using a variable, 
constant, or literal value will pass a parameter by value. 

The first parameter to any InLine call is the value which specifies the trap number. The trap number 
indicates which Toolbox routine is to be called. All subsequent parameters must exactly match the 
number and type of the parameters for the particular Toolbox routine being called. 

Warning; Because there is no type checking, none of THINK Pascal’s usual im¬ 
plicit type-coercion will be performed (e.g., integer to longint). All parameters 
must match exactly the parameters for the particular Toolbox routine being called. 

373 



THINK Pascal User Manual 


Note: The InLine procedures are provided only for compatibility with 
Macintosh Pascal. THINK Pascal provides direct access to the Macintosh toolbox 
and therefore the only need for InLine is for porting Macintosh Pascal programs 
which used these routines. 

10.9.11 The Generic Procedure 

Generic(Instr, Regs) 

I ns t r an expression with an integer value that indicates the instruction to be 

executed. 

Regs a variable-reference of type RegisterRecord (see below) that indicates 

the values to be written to the MC68000 registers. 

Generic lets you call register-based Macintosh ROM routines. It can also be used to execute any 
machine-language code that you have stored in a Pascal data structure. 

RegisterRecord denotes a data structure consisting of 13 32-bit values - five address register 
values (AO . . A4), followed by eight data register values (DO . . D7). The exact type of this structure 
is immaterial. For example, you could declare: 

var regs: record 

a: array[0..4] of longint; 
d: array[0..7] of longint 

end; 

The register values passed to Generic are written to the MC68000 registers. Then the one-word 
instruction denoted by the Instr argument is executed. Finally, the Regs structure is updated 
with the (possibly) new values of the MC68000 registers before Generic returns to the program. 

Usually, Generic will be used to execute a register-based Toolbox trap. In such cases, the value 
you pass to Generic via the Instr argument is the trap value. 

The Instr argument to Generic does not have to be a trap value, it can be any 16-bit MC68000 
instruction. 

Note: The Generic procedure is provided only for compatibility with Macintosh 
Pascal. THINK Pascal provides direct access to the Macintosh toolbox as well as 
the ability to call assembly language routines. Therefore, the only need for 
Generic is for porting Macintosh Pascal programs which used this routine. 


374 



Language Reference 


17 


10.9.12 The Macsbug Support Procedures 

Debugger 

DebugStr(message) 

Message a string-type value. 

Debugger and DebugStr cause a User Break which interrupts the execution of the program and 
transfers control to the Macsbug low-level debugger. If DebugStr is used, the message 
argument is displayed. 

If Macsbug is not installed, then calls to Debugger and DebugStr give the run time error 
message “Macsbug/TMON not installed.” 

10.9.13 Member Function 

Member(r, t) 

r an object-reference expression, 

t a type-identifier of a reference type. 

Member returns true if r references an object of type t. 

10.9.14 The Time-of-Compilation Functions 

compdate 

comptime 

Returns string-type 

These return the day and time that the enclosing file was compiled. Compdate returns the date in 
the form mm/dd/yy (e.g., 8/24/90). Comptime returns the time in the form hh:mm: ss XM 
(e.g., 11:05:35 AM). 


375 





THINK Pascal" 

PART FIVE 

Utilities 

18 Project Utilities 

19 The Profiler 

20 The Pascal Source Converter 

21 Resource Description Files 

22 Using SARez 

23 Using SADeRez 

24 Using SAPostRez 





Project Utilities 

18 


Introduction 

This chapter describes Project Utilities, a utility program that backs up and prints files from THINK 
Pascal projects faster than you could from the Finder or THINK Pascal. You can back up all the files 
in your project, including libraries and resource files, to another disk to guard against crashes. You 
can print out the files in your project in succession, one after the other. Project Utilities lets you 
select which files to back up or print, according to file type, creation date, or some other criteria. 

Topics covered in this chapter 

• Using Project Utilities 

• Selecting files 

• Printing files 

• Backing up files 

Using Project Utilities 

If you installed THINK Pascal according to the instructions in Chapter 2, “Installing THINK Pascal,” 
Project Utilities is in the THINK Pascal 4.0 Folder. 

Note; Project Utilities must be in the same folder as THINK Pascal. Otherwise, it 
will not be able to find all the files in a project. 



THINK Pascal User Manual 


To start Project Utilities, double-click on its icon. Choose a project from the standard file dialog that 
Project Utilities displays. You’ll see a Project Utilities project window like this: 


22 files in project, 311 K total. ^ 


File Name 

File Size 

File Type 

Directory 

L 

pRuntime.Lib 

9668 

Pascal Library 

« Libraries » 

o 

Interface .lib 

PrintCalls.lib 

22010 

2596 

Pascal Library 
Pascal Library 

ecSystem Root & 

« Libraries » 

m 

Quickdraw.p 

348 

Source File 

«lnterfaces» 

jjlji 

Printing.p 

9474 

Source File 

«Interfaces » 


Script .p 

27318 

Source File 

«Interfaces » 

• 

DialogUtils.p 

11393 

Source File 

(Project Root) 


EmbedDefProc.p 

2430 

Source File 

(Project Root) 


Objlntf.p 

1282 

Source File 

«Interfaces » 



380 








































































































Project Utilities 


18 


The Project Utilities window displays the name, size, type, directory, last date modified, and last 
date backed up for every file in your project. If Project Utilities can’t find a file, it displays its name 
in italics and writes “File not found” in the Directory field. To see the fields beyond the right edge 
of the window, use the scroll bar at the bottom of the window. If you have a large screen, you can 
resize the window so it looks like this: 


22 nw In projvot, 311 K total. 


ObJectOrom Project 


Fife Nim 

Fife Six* 

Fife 

DtrMtorf 

luOMtfM 

Book *6 (fe 

ItRwittnvlfc 

9668 

Puotl Lfervy 

«Lftr»4**» 

09/26/89 2240 

N*v*r 

lnt*rf*o*.lt> 

22010 

Paul Ifcrvy 

•SfilM RnI> 

07/30/89 18X11 

N*v*r 

PrlntClIB.hb 

2596 

Pwool L®r*ry 

«Ltrori*f » 

07/30/89 18 02 

N*v*r 

Qutofc(fcr«v.p 

348 

Sovoo Fit* 

«bit*rfooo* » 

08/01/89 16:48 

N*v*r 

Prating* 

9474 

Saro* Fit* 

«htwfM*i» 

07/31/89 00 04 

06/12/89 03:47 

Script* 

27318 

Sovo* Fit* 

«ht*rfoo»*» 

07/31/89 01 XI 

06/12/89 03:47 

ch* login ni.p 

11393 

SovooFit* 

(Prtjni Root) 

10/16/89 22:33 

N*v*r 

Lm6»d>*ffYoc p 

2430 

Sokro* Fit# 

(ProjMt RmO 

07/17/89 07 30 

09/07/89 00:30 

Cbjhtf* 

1282 

Soirot F11* 

«lnt«rfao*s» 

04/09/88 12:38 

06/12/89 03:47 

ODkitt-p 

9306 

So*roo Fit* 

(Prafeot RmO 

10/16/89 22:41 

08/14/89 18:37 

00ft>*f*p 

11738 

Sokroo Fit# 

(ProjMt RmO 

10/19/89 11 :36 

08/14/89 18:37 

COM*™** 

8712 

Sokvoo Fit* 

(PrtjNt RmO 

10/16/89 22:33 

08/14/89 18:37 

OOTUrt* 

2081 

Sotro* Fit* 

(ProjMt RmO 

09/07/89 00:41 

08/14/89 18:37 

00 TVMow i 

13162 

Sokro* Fit* 

(Pr*jMt RmO 

10/19/89 1237 

08/14/89 18:37 

OOTDrowVMow * 

4061 

Soirc* Fit* 

(ProjMt RmO 

10/14/89 11 06 

08/14/89 18:37 

OOTPIcVMowi 

4014 

Sou-o* Fit* 

(ProjMt RmO 

10/14/89 11 38 

N*v*r 

OOTShop** 

5483 

Sokro* Fit* 

(ProjMt RmO 

10/13/89 16:10 

08/14/89 18:37 

OOCvtnt* 

2569 

Sokro* Fit* 

(ProjMt RmO 

10/19/89 1237 

08/14/89 18:37 

00 In it* 

6442 

Sovo* Fit* 

(ProjMt RmO 

10/19/89 1237 

08/14/89 18:37 

ObjootOrowi 

683 

Sokr-o* Fit* 

(ProjMt RmO 

10/16/89 22:35 

08/14/89 18:37 

0b>*o<0r«w Projool 

159788 

Pr*>oi Fit* 

(ProjMt RmI) 

10/19/89 13:47 

N»v*r 

Objoot&row.Rcre 

4566 

Rttoirw Fit* 

(ProjMt RmO 

10/19/89 11 :13 

08/14/89 18:37 


You can open several projects at once. To open another project, choose Open... from the File 
menu and select the project. To close the project in the front window, choose Close from the File 
menu. 

Reading the display 

Most of the fields in the Project Utilities project window are self-explanatory. The File Size field 
displays the size of the file in bytes. The Last Modified field displays the date when the file was last 
modified. The Backed Up field displays the date the file was last backed up or “Never” if was never 
backed up. 

The other fields need a little more explanation. The File Type field displays the type of the file. It 
can be one of these: 

File Type 

Source File 

Pascal Document 
Pascal Library 
C Library 


Description 

Any text file or source file except a THINK Pascal source file 
saved as Entire Document 

A THINK Pascal source file saved as Entire Document 
A library created with THINK Pascal 
A library created with THINK C 


381 






THINK Pascal User Manual 


File Type Description 

MPW Object File An object file (. o file) created with MPW 

Project File A THINK Pascal project file 

Resource File A resource file created with ResEdit or Rez 

The Directory field displays the folder that contains the file. If the file is in the THINK Pascal tree, 
the folder name is in angle quotes («»). If it’s in the project tree, the folder name is in parentheses 
(()). If it’s in neither tree, Project Utilities lists the full pathname . 

Note: If you’re not sure what the THINK Pascal and project trees are, see 
“Organizing Your Files” in Chapter 7. 

This really isn’t as confusing as it may sound. This chart explains what the entries mean: 


If it looks like... 

«flle-name» 

the file is in... 
the THINK Pascal 

tree 

For example: 

«Libraries» 

means the file is in 

the Libraries folder in 
the THINK Pascal folder 

( file-name) 

the project tree 

(MyLibs) 

the MyLibs folder in your 
project’s folder 

folder : file-name 

neither tree 

HD20:Math 

the Math folder on the 
disk HD2 0 

^System Root* 

the same folder as 
THINK Pascal 



(Project Root) 

the same folder as 
your project 




Printing the project window 

To print out the contents of the Project Utilities project window, choose Print Project... from the 
File menu This command displays the standard Print dialog and prints the window. 

Saving a list of files 

To save a list of the full pathnames of the files in your project, choose Write Project Listing... 
from the Project menu. This displays a standard save dialog that lets you choose where to save the 
listing. 


382 



Project Utilities 18 


Selecting Files 

Project Utilities lets you select any number of files to back up or print. You can choose them your¬ 
self or use the commands in the Project menu. You can select files in Project Utilities project 
window the same way you do in the Font/DA Mover: 

To select... Do this... 

A single file Click on the file name 

A range of files Hold down the Shift key and click on a file name 

Many individual files Hold down the Command key as you click on each file 

Selecting files by type 

To select all the files of a certain type, use the Select By File Type command. It shows a hierarchi¬ 
cal menu that lets you select a type. See “Reading the display” above for an descriptions of the file 
types. 

Selecting files by folder 

To select all the files from a certain folder or tree, use the Select Files From command. It shows a 
hierarchical menu that lets you select one of these: 

-THINK Pascal Tree- Files in the THINK Pascal tree. 

(Project Tree) Files in the project tree. 

The hierarchical menu also has entries for each folder that contains a file in the project. 

Selecting files by ending 

To select all the files that end in a certain suffix, use the Select Files Ending In command. It 
shows a hierarchical menu that lets you select one of these: 

.p THINK Pascal source files (including files saved as Entire Document) 

.c THINK C source files 

.h THINK C header files 

.o MPW object files 

.Lib THINK C or THINK Pascal libraries 


383 



THINK Pascal User Manual 


Selecting files by date 

To select all the files that were modified after a certain date, use the Select By Date... command. It 
displays this dialog: 


Select files modified after: 

October 1 |tl 31 1 


1990 


Till ffool EToo 



Cancel §§. 

I J 


Project Utilities initially displays the current date and time. To change the time, click on the arrows 
to the left of each item. The longer you hold down the mouse, the faster the item changes. The time 
selected here is 12 noon on October 31, 1990. 

Selecting flies for backup 

To select all the files that need to be backed up, use the Select If Backup Needed command. It se¬ 
lects all the files that have never been backed up or that have been modified since they were last 
backed up. 

Printing Files 

Project Utilities can print several text files in succession, one after the other. 

Note: Project Utilities cannot print THINK Pascal documents saved as Entire 
Document. You can print these from THINK Pascal or you can open them in 
THINK Pascal and save them again with the Entire Document option unchecked. 

Also, Project Utilities does not “pretty-print” files like THINK Pascal does. It does 
not print Pascal keywords in bold face and may indent some lines differently. 




Project Utilities 


18 


To print all the selected text files, choose Print Selected Files... from the File menu. You’ll see 
the standard Print dialog with a few extra options: 


Quality: O Best (5) Faster_Q D raft 

Page Range: ® Rll Q From: \\ ] To: [ | 

Copies: 11 | 

Paper Feed: <•> Automatic O Hand Feed 


H Print Pages In Reuerse Order XR 
□ Frame Printing Rrea XF 
0 Print Page Headers XH 

[Printing Font:] Geneua-9 


Time Stamp: 

<§) File s Modification Date XM 


Cancel 


O Date of Printing XP 


Here’s what the extra options mean: 

Print Pages in Prints the pages from last to first, instead of first to last. 

Reverse Order 

Frame Printing Prints a border around each page. 

Area 


Print Page Prints a header on each page, containing the page number, the file 

Headers name, and a time stamp. You can choose what time to print with 

the Time Stamp option described below. 


385 









THINK Pascal User Manual 


Printing Font Displays a dialog that lets you select the font, type size, and style 
used for printing. The default is the font and size specified in the 
THINK Pascal Source Options... dialog. To change it, select a font 
and size from the pop-up menus. To use a size that’s not in the 
menu, type it into the box. Change the font style with the check 
boxes. The box outlined in grey contains a sample of what a line of 
your code will look like. For example, this dialog is set up for nine 
point Geneva, plain: 


Font: | Geneua 
Size: cd [mi 


CEZ) 

[ Cancel X. ] 


El Plain SIP 

□ Condensed XN 

□ Entended XE 


□ Bold XB 

□ Italic XI 

□ Underline XU 


□ Outline XO 

□ Shadow XS 


hPE“.tabV1dth :■ 4 » Ch*rVidth(CHR($00)); 


Time Stamp Lets you choose which time is printed in the page headers (if you 

have Print Page Headers selected). These are the choices: 

• File’s Modification Date. The date the file was last modified 

• Date of Printing. The date you print the file. 


Backing Up Files 

Project Utilities lets you back up your project’s files to another folder, disk, or a set of floppy disks. 

Note: Project Utilities works in the background under MultiFinder. While backing 
up, you can switch to another application or move and resize the project window. 
However, you cannot close the project window or bring another Project Utilities 
window to the front. 






Project Utilities 


18 


To start, select all the files you want to back up. Usually, you’ll want to choose Select If Backup 
Needed to select only the files that have never been backed up or that were modified since you 
last backed them up. Then choose Backup... from the Project menu. You’ll see this dialog: 


IS] ObjectDraui... 

I Uect 1 

f P™e ] 

II o* II 

[ Open ] 

[ Cancel ] 

S Back Up Selected Files Only 96S 
778 K free on “ObjectDraui Backup”. 


g) ObjectDraui Backup 



O 

o 


Project Utilities lets you save a back up to any device you can use in the Finder, such as a hard 
drive or floppy disks. The Back Up... dialog works pretty much like a standard file dialog box. The 
message at the bottom of the dialog tells you how much space is free on the device selected. If 
Back Up Selected Files Only is checked, Project Utilities will back up only the files you checked. 
Otherwise, it will back up all the files in the project. The OK button (or pressing Command-Enter) 
tells Project Utilities to go ahead and do the back up. The Open button lets you open a folder. If 
you select a folder and click on the OK button, Project Utilities will place your files in that folder. 

Note: You cannot back up your files to the same folder that your project is in. And 
to be certain your backup is secure in case of a disk crash, you should back up 
your files to a different disk. 


387 






THINK Pascal User Manual 


As Project Utilities backs up your project, it displays its progress in the top of the project window, 
like this: 


(Backup in progress) 

Press Command-Period to cancel this operation. 

631296 bytes free on "ObjectDraw Backup". 

File: ObjectDraw Project 
1 files to go. 


File Name 

File Size 

File Type 

Directory 


L 

ODTVindow.p 

13162 

Source File 

(Project Root) 


£ 

ODTDraw Vindow .p 

4061 

Source File 

(Project Root) 



ODTPicWindow.p 

4014 

Source File 

(Project Root) 



ODTShape.p 

5485 

Source File 

(Project Root) 



ODEvent.p 

2569 

Source File 

(Project Root) 


|| 

ODInit.p 

6442 

Source File 

(Project Root) 


;|| 

ObjectDraw .p 

683 

Source File 

(Project Root) 








■ 



WB 




mm 




As Project Utilities copies a file, it deselects it and notes the back up date and time in the file. You 
can cancel the back up at any time by pressing Command-. (Command-Period). 

If you’re backing up to a floppy, Project Utilities displays a dialog box asking you to insert another 
disk when the first one is full. 


388 




















































































































Project Utilities 


18 


If the destination disk or folder already has a file with the same name as one of the files in your 
back up, Project Utilities asks you what to do: 


“DialogUtils.p” already exists on the destination. Do you 
want to cancel the backup, replace the existing file, or 
skip this file? 


Skip 3€S 

V .._/ 

□ Don't Rsk Rgain 96D 


Replace 96R 


i 


Cancel 96. 




You can choose to skip the file, replace the file, or cancel the back up. If you check the box labeled 
“Don’t Ask Again,” Project Utilities will do the same thing whenever it comes across a file that’s al¬ 
ready in the destination. For example, if you check “Don’t Ask Again” and click on the Replace File 
button, Project Utilities replaces files in the destination whenever it finds duplicate names. 


389 






The Profiler 
19 


Introduction 

This chapter shows you how to use the THINK Pascal code profiler. The profiler collects statistics 
about your program, including the time spent in each routine. 

Topics covered In this chapter: 

• Using the profiler 

• Reading the report 

• Summary 

Using the Profiler 

To use the profiler in your project, follow these steps: 

• Turn on the Profile option in the Compile Options... dialog. 

• Turn on the Debug and Names options (using the project window or the Debug and 
Names directives) for every routine you want measured. If the Debug option is off for a 
routine, the profiler will not collect statistics for it. If the Names option is off for a rou¬ 
tine, the profiler won’t list its name but ???????? instead. 

The profiler records information for every function and procedure call. It collects statistics for up to 
two hundred routines. If there are any more , it lumps their statistics together under the name 
catchall. It can handle a calling chain of up to two hundred routines. If the calling chain 
becomes longer (which is possible in a heavily recursive program), the profiler will stop collecting 
statistics. When your program exits, the profiler writes a report to the Text Window. To see a 
sample report, see “Reading the Report, ” below. 

You can control how the profiler profiles your code. For example, you can increase the number of 
routines it collects statistics for or print out a report before your program exits. To call the routines 
that control the profiler, follow these steps: 

• Include the file Prof ile. p in your project. If you installed THINK Pascal according to 
the instructions in Chapter 2, “Installing THINK Pascal,” it should be in your THINK 
Pascal 4.0 Folder 

• Add Prof ile r to the uses clause of every unit and program that calls profiler 
routines. 


391 




THINK Pascal User Manual 


These are the routines control the profiler. For detailed descriptions, see “Summary,” below. 

• To collect statistics for more than two hundred routines, call InitProfiler It takes 
an argument specifying how many routines to collect statistics for, up to 32,768. 

• To stop collecting statistics temporarily, set %_PTrace to FALSE. To start collecting 
statistics again, set %_PTrace to TRUE. 

• To print out the statistics collected so far, call DumpP ro f ile or 
DumpProf ileToFile. DumpProfile prints the statistics in the Text Window. 
DuinpProf ileToFile takes an argument specifying a file to print to. 

• To reinitialize the profiler without stopping it, call ResetProf ile. 

• To stop the profiler, call TerminateProfile. 

Reading the Report 

The profiler logs the time spent and the number of statements executed for each routine and prints 
the results to the Text Window. This report was produced with the Long Names on: 

THINK Pascal Procedure Profile 

All time is measured in milliseconds, 
rounded down to the nearest millisecond. 

An asterisk (*) next to a routine name indicates that that routine 
was left via a nonlocal GOTO, EXIT to an uplevel routine, 
or "longjmp”-style context restoration. 


Elapsed Time = 

289945 

Measured Time = 

1027888 

Total Calls = 

5052 


Routine 

Min 

Max 

Avg 

Total 

% 

Times 

Name 

Time 

Time 

Time 

Time 

Time 

Called 

SORTING 

312619 

312619 

312619 

312619 

30.41 

1 

QUICKSORT 

1 

39373 

129 

436725 

42.49 

3367 

PARTITION 

4 

159 

6 

11282 

1.10 

1683 

BUBBLESORT 

267262 

267262 

267262 

267262 

26.00 

1 


Note: For more information on the Long Names option, see “Names { $N±}," 
Chapter 15. 


392 




The Profiler 


19 


This describes the report’s headings: 


Heading 

Min Time 
Max Time 
Avg Time 
Total Time 
% Time 

Times Called 


Description 

The minimum time spent in 

The maximum time spent in the routine. 

The average time spent in the routine. 

The total time spent in the routine. 

The percentage of program’s time spent in the routine. 
The number of times the routine was called. 


Time is measured in milliseconds (thousandths of a second). If a function did not exit normally and 
aborted in one of the following ways, the profiler puts an asterisk by its name: 

• Called exit 

• Used a non-local goto. 


Summary 

These procedures control the profiler: 

function InitProfiler (nEntries: integer): Boolean; 

This lets you specify how many routines you want statistics for, up to 32,768. It must be the first 
statement in your program. You need to call this routine only if you want to collect statistics for 
more than 200 routines. When you turn on the Profile option, THINK Pascal automatically 
initializes the profiler and reserves space for 200 routines. 

This routine returns true if it can initialize the profiler and false if it can’t. If this function can’t 
initialize the profiler, you’re probably asking it to collect statistics for too many routines. Each 
function or procedure you collect statistics for takes up 94 bytes, and each function or procedure 
call takes up 14 bytes. 

procedure DumpProfile; 

This dumps the current statistics about your program to the Text Window, 
procedure DumpProfileToFile (fileName: Str255); 

This dumps the current statistics to the file fileName in the default volume. If the file already ex¬ 
ists, the profiler will delete and overwrite it The default volume is usually the folder your project is 
in, unless you’ve changed it with SetVol. 

procedure ResetProfile; 

This reinitializes the profiler and its statistics. Use this to collect two different sets of statistics in the 
same run of your program. 

procedure TerminateProfile; 

The stops the profiler. After you call it, the profiler collects no more statistics. 


393 



THINK Pascal User Manual 


var %_PTrace: Boolean; 

This lets you turn off the profiler over certain parts of your program. To stop collecting statistics, set 
%_PTrace to FALSE. To start collecting statistics again, set %_PTrace to TRUE. 



The Pascal Source Converter 

20 


Introduction 

The Pascal Source Converter is an application that helps you translate programs written for Apple’s 
MPW Pascal for use with THINK Pascal. The Pascal Source Converter: 

• converts MPW Pascal directives to THINK Pascal directives, 

• processes MPW Pascal $ I include directives, 

• processes $ IFC directives, 

• converts nested comments into unnested comments, 

• resolves uses clauses into a form compatible with THINK Pascal, and 

• converts source code according to a ‘differences’ file. 

The Pascal Source Converter was initially designed to convert the MacApp source files so they can 
be used with THINK Pascal. Since the converter is script driven, you can use it to convert programs 
that you’ve already written for MPW Pascal so you can use them in THINK Pascal. The Pascal 
Source Converter is in the MacApp 2.0 for THINK Pascal 4.0 folder. For information 
about installing the Pascal Source Converter on your disk, see Chapter 2, “Installing THINK Pascal.” 

What you should know 

You should be familiar with THINK Pascal and with MPW Pascal. Particularly, you should know 
how the MPW Pascal compiler directives work. 

Topics covered In this chapter 

• Scripts 

• Input and output directories 

• Specifying directories and file names 

• Converting Files 

• Pascal Source Converter directives 

• A sample script 

Scripts 

The Pascal Source Converter uses a script to specify which files need to be converted and to con¬ 
trol how a file should be converted. Scripts are files of type TEXT. By convention, scripts end with 
the suffix .Script. 

Note; If you want the Pascal Source Converter to open scripts automatically when 
you double-click on them, set the creator to MACv. 


395 



THINK Pascal User Manual 


A Pascal Source Converter script consists of several directives. Pascal Source Converter directives 
look just like regular Pascal compiler directives. The converter processes these directives in scripts: 


$BEEP 

$CREATOR 

$DEPEND 

$DIFFS 

$DIR 

$ELSEC 


$ENDC 

$IFC 

$INCLUDES 
$INPUT 
$LINE 
$NOUSES 


$OUTPUT 

$PORTABLE 

$SETC 

$SKIP 

$USES 


To learn how to write a script, you might want to look at the file MacApp. Script in the folder 
MacApp 2.0 for THINK Pascal 4. 0. This is the script that the Pascal Source Converter uses 
to convert the Apple MacApp source files into a form that THINK Pascal can use. 


Input and Output Directories 

The Pascal Source Converter processes either one file or every file in a specified directory and 
places the converted file in an output directory. Use the $OUTPUT directive to specify the directory 
that will receive the converted file. Use the $ INPUT directive to specify the file or directory that 
you want to convert. All of your scripts will have lines that look like this: 

{$OUTPUT directory } 

{$ INPUT directory or filename } 

The $OUTPUT directive must come before the $ INPUT directive. Both directories must already 
exist. The next section tells you how you can have a user create a directory from a script. 

Note: The input directory must not be the same as the output directory. 


Specifying Directories and File Names 

In Pascal Source Converter scripts, directory names and file names are strings that contain the full 
path to the file or directory. You can set a compile-time variable to a string that contains a path 
name and use it to modify a directory string. 

{$SETC RootDir = 'MyDisk:Master Folder: 1 } 

{$SETC InputFolder = (RootDir) *SourceFolder: 1 } 

{$SETC OutputFolder = (RootDir)'DestinationFolder: 1 } 

{$OUTPUT OutputFolder } 

{$INPUT InputFolder } 

To use the value of a compile-time variable to modify a file name or directory, enclose the variable 
name in parentheses, and place it before the quoted part of the string. Note that the folder names 
end with a colon. 


396 




The Pascal Source Converter 


20 


The Pascal Source Converter can prompt the user to supply a directory name ora file name. If the 
string begins with a special character, the Pascal Source Converter displays a dialog that lets the 
user choose a file or folder. The converter uses the rest of the string as a prompt 

Character Prompt the user for... 

$ an existing directory 

# a new directory name 

? an existing file name 

For instance, these directives let the user choose an existing input directory and create a new 
output directory: 

{$SETC InputDir = 1 $Please find the input directory'} 

{$SETC OutputDir = '#Please create a new directory'} 

{$OUTPUT OutputDir} 

{$INPUT InputDir} 

Converting Files 

Once you’ve specified the input and output directories, the Pascal Source Converter converts every 
file in that directory and places a converted copy of the file in the output directory. The Pascal 
Source Converter is a non-destructive converter. It won’t alter the original file. However, you 
should not set the input directory to be the same as the output directory. 

$IFC Conditional compilation directives 

The Pascal Source Converter processes conditional compilation ($IFC) directives. If it encounters a 
compiler variable that is defined either in the converter script or in the source file, the effect is the 
same as conditional compilation. For instance the converter turns these lines: 

{$SETC WeAreTesting = TRUE } 

procedure MyProc (a: Integer); 

begin 

someGlobal := a; 

{$IFC WeAreTesting } 

writeln('The value of a is: ', a:l); 

{$ENDC} 

end; 

into this: 

procedure MyProc (a: Integer); 

begin 

someGlobal := a; 

writeln('The value of a is: ', a:l); 


end; 



THINK Pascal User Manual 


The $SETC directive can appear either in the converter script or in the source file. The Pascal 
Source Converter never processes $SETC directives that appear in the implementation part of a 
unit. 

If a compiler variable is undefined at the time that the Pascal Source Converter encounters it, the 
converter leaves the lines alone. The Pascal Source Converter never converts any $IFC directives 
of the form {$IFC NOT UNDEFINED THINK_Pascal } or { $IFC UNDEFINED 
THINK_Pascal }. All of the code to the matching $ENDC is sent directly to the output file. 

Note: THINK Pascal defines THINK_Pascal as TRUE when you’re in the THINK 
Pascal environment Your script and your program should never define 
THINK_Pascal. 

$1 Include file directives 

When the Pascal Source Converter encounters an MPW Pascal $1 (include file) directive, it either 
includes the contents of the named file to the file that contains the directive, or it adds the file to the 
uses clause. 

If the $ I directive contains the name of a file qualified by an MPW Shell variable, the $ I directive is 
replaced by the contents of the file. For instance, if the Pascal Source Converter encounters a 
directive like this: 

{$1 $$SHELL(MAPInterfaces)UMacApp.p} 

the contents of UMacApp. p are inserted where the directive appears. 

Note: You can use the $SETC directive to set the value of an MPW Shell variable. 

If the $1 directive isn’t qualified by an MPW Shell variable and the $1 directive is in the interface 
part of a unit, the file name is converted to a unit name and it’s appended to the end of the uses 
clause. For instance, the Pascal Source Converter converts this fragment: 

unit UMacApp; 
interface 

uses SysEqu, UMacAppUtilities; 

{$1 UAssociation.pl 
{$1 UList.pl 

incrementation 

{ more code here } 


end. 


398 



The Pascal Source Converter 


20 


to this: 

unit UMacApp; 
interface 

uses SysEqu, UMacAppUtilities, UAssociation, UList; 
implementation 

{ more code here } 


end. 

If the $ I directive is not qualified but does not appear in the interface part of a unit, the converter 
treats it the same way as it does qualified $1 directives. 

Compiler directives 

The Pascal Source Converter converts some MPW Pascal compiler directives into equivalent THINK 
Pascal compiler directives. The Pascal Source Converter also removes MPW Pascal compiler direc¬ 
tives that THINK Pascal does not support. The Pascal Source Converter can convert equivalent 
compiler directives in either a portable or non-portable way depending on the setting of the 
$PORTABLE converter directive. For example, if your script includes the directive $PORTABLE+, 
this directive: 

{ $D+} 

gets converted to: 

{$IFC UNDEFINED THINK_Pascal} 

{ $D+} MPW Pascal directive to turn on Macsbug names 

{$ELSEC} 

{$N+} THINK Pascal directive to turn on Macsbug names 
{$endc} 

If the Pascal Source Converter is converting a main program instead of a unit, it automatically sup¬ 
plies the THINK Pascal $1- directive to suppress Macintosh Toolbox initialization at the beginning 
of the file. If the $PORTABLE+ directive is on, the converter adds these lines to the beginning of 
the file: 

{$IFC NOT UNDEFINED THINK_Pascal} 

{$ 1-1 
{$ENDC} 

Comments 

The Pascal Source Converter converts nested comments (which MPW Pascal allows) into unnested 
comments. For instance: 

{ This comment {contains a comment} inside it } 


399 



THINK Pascal User Manual 


becomes: 

{ This comment ( * contains a comment * ) inside it } 

Note: The converter places a space between the parentheses and the asterisks. 

Differences 

Sometimes, it’s just not possible to convert a program from MPW Pascal to THINK Pascal without 
altering the source directly. If you’re working with someone else’s MPW Pascal code, you may not 
be able to simply distribute translated code. The Pascal Source Converter contains a mechanism 
that applies a list of specific differences to the original MPW Pascal file to create a new THINK 
Pascal file. 

Note: If you’re using the Pascal Source Converter to convert your own files, you 
won’t need to use this feature. It’s primarily designed for those who need to 
convert MPW Pascal source code without actually distributing modified code. 

When the Pascal Source Converter opens a file either through an $ INPUT directive or in the course 
of processing a $1 directive, it looks in the differences folder (specified with a $DIFFS directive) 
for a folder with the same name as the folder that contains the file. It th-sn looks within that folder 
for a file with the same name as the file it’s processing, but with . Dif f appended to it. If it finds 
one, it merges the changes into the resulting file. 

For example, assume that you used the $DIFF directive to tell the converter that the differences 
folder is the folder AllDif f s. As the Pascal Source Converter processes a file called My Source. p 
(which resides in a folder called MyFolder), it looks in the folder AllDif fs for a folder called 
MyFolder. Then it looks in MyFolder for a file called My Source .p. Dif fs. If it finds it, it 
applies the changes to the source file. 

To create a . Dif f file, you need to use the MPW Compare tool and give it this command: 
Compare newfile oldfile > newfile.Diff s 
Note: The order of the files is extremely important! 

Pascal Source Converter Directives 

This section lists the directives you can use in Pascal Source Converter scripts. Don’t forget that you 
can use these directives in source files as well. 

{$BEEP} 

Beep the speaker. This directive is useful when you’re debugging your script. 

{$CREATOR 'jcccc' } 

Set the creator of converted files to ' xxxx '. The default is ' P JMM'. 


400 



The Pascal Source Converter 


20 


{ $depend unit-name unitl unit2 ...} 

Specify dependencies among units. As the converter processes MPW Pascal $ I directives, it may 
add unit names to the uses clause of units. These units may in turn require other units. 

For instance, the MPW file ULoMem. p uses $1 directives to include SysEqu. p and Devices . p 
which the Pascal Source Converter converts to unit names in a uses clause. Because ULoMem uses 
symbols from SysEqu and Devices in its interface part, any unit that uses ULoMem also needs to 
use SysEqu and Devices. To make sure that the converter knows this you need a line like this in 
your script: 

{$DEPEND ULoMem SysEqu Devices} 

You can read this directive as “ULoMem uses SysEqu and Devices, so any unit that uses ULoMem 
should also use SysEqu and Devices.” 

So the MPW Pascal line: 

uses ULoMem; 

is converted to the THINK Pascal line 

uses SysEqu, Devices, ULoMem; 

$DEPEND applies to the next $INPUT directive. 

{$DIFFS directory } 

Specify the directory that contains the folders that contain . Dif f files. 

{$DIR directory } 

Set the default directory for unqualified files names to be directory. An unqualified file name 
doesn’t include any directory information. For instance when the Pascal Source Converter 
processes these lines, 

{ $DIR 'MyDisk:PascalFile: 1 } 

{$INPUT 1 MyFile.p 1 } 

it will look for the file MyFile. p in MyDisk : PascalFile :. 

{$ ifc condition } 

{$elsec} 

{$ENDC} 

These directives work the same way as the Pascal compiler directives. If a compiler variable is un¬ 
defined, the Pascal Source Converter leaves the entire conditional (up until the closing $ENDC) 
alone. The Pascal Source Converter also leaves alone directives of the form $IFC [NOT] 
UNDEFINED THINK PASCAL. 


401 



THINK Pascal User Manual 


{$INCLUDES directory } 

This directive tells the Pascal Source Converter where to find include files in unqualified $1 
directives. An unqualified $1 directive looks like this: 

{$1 AnIncludeFile.pl 

Qualified $ I directives use an MPW Shell variable to specify their directory. 

The $ INCLUDES directive applies to the next $ INPUT directive. For instance, in this script 
fragment: 

{$OUTPUT SomeDirectory } 

{$INPUT SourceDirectory } 

{$INCLUDE Thelncludes } 

{$INPUT AnotherSource } 

the Pascal Source Converter will look for include files in the directory Thelncludes only for the 
files in AnotherSource. 

{$INPUT directory-or-filename } 

Process all the files in the specified directory or the specified file. After processing the file, the 
Pascal Source Converter places the converted version of the file in the output directory. Your script 
must have at least one $ INPUT directive after an $OUTPUT directive. For instance, this script: 

{$OUTPUT OutputDir) 

{$INPUT 'MyDisk:SomeFolder:MyFile.p'} 

{$INPUT 'MyDisk:AnotherFolder} 

{$INPUT SomeFolder) 

will convert the file MyFile. p, all the files in the folder AnotherFolder, and all the files in the 
directory specified in the script variable SomeFolder into the folder specified by OutputDir. 

{$LINE * string' ) 

Insert the string into the output file. This directive is useful when you’re debugging scripts. 

{$NOUSES unit-name unitl unit2 ... } 

When the Pascal Source Converter encounters the unit unit-name , it removes the specified units 
from the uses clause. If you supply an asterisk (*) as the unit-name , the Pascal Source Converter 
removes the specified units from every uses clause. $NOUSES applies to the next $ INPUT 
directive. 


402 



The Pascal Source Converter 


20 


{$OUTPUT directory } 

Set the output directory. The output directory is where the Pascal Source Converter places the con¬ 
verted files.The $ OUTPUT directives specifies where to place the files processed by the next 
$ INPUT directive. This means that an $OUTPUT directive must precede an $ INPUT directive. If 
you specify another $OUTPUT directive, it will apply to the files processes by the next $ INPUT 
directive. For instance, in this script: 

{$OUTPUT FirstDir) 

{$INPUT SourcelDir) 

{$INPUT Source2Dir} 

{$OUTPUT SecondDir) 

{$INPUT Source3Dir) 

the Pascal Source Converter places the converted files from SourcelDir and Source2Dir in 
FirstDir and the converted files form Source3Dir in SecondDir. 

{$PORTABLE±) 

Determines how the converter process the MPW Pascal compiler $D (Macsbug names ) directive. If 
your script contains the directive $PORTABLE+ the converter changes the directive so you can use 
the source file with either THINK Pascal or MPW Pascal. For example, if your script includes the 
directive $ PORTABLE*, this directive 

{ $D+) 

gets converted to 

{$IFC UNDEFINED THINK_Pascal) 

{ $D+ } { MPW Pascal directive to turn on Macsbug names } 

{$ELSEC) 

{$N+} { THINK Pascal directive to turn on Macsbug names } 

{$ENDC} 

If the Pascal Source Converter is converting a main program instead of a unit, it automatically sup¬ 
plies the THINK Pascal $1- directive (suppress Macintosh Toolbox initialization) at the beginning 
of the file. If the $PORTABLE+ directive is on, the converter adds these lines to the beginning of 
the file: 

{$IFC NOT UNDEFINED THINK_Pascal} 

{$1-1 
{$ENDC} 

The $ PORTABLE directive applies to the next $ INPUT directive. For example: 

{$PORTABLE-} 

{$INPUT NonPortableSourceDir} 

{$PORTABLE+} 

{$INPUT PortableSourceDir} 


403 



THINK Pascal User Manual 


The files in NonPortableSourceDir will have all MPW Pascal $D directives converted to 
THINK Pascal $N directives, but the files in PortableSourceDir will have the conditional 
compilation wrapper so you can use the source file with either compiler. 

The default is { $ PORTABLE -} . 

{$SETC compiler-variable = value ) 

This directive works just like the regular Pascal $SETC directive. It sets the specified compiler vari¬ 
able to the specified value. In Pascal Source Converter scripts you can set a compiler variable to a 
string. 

To prompt the user for a directory name or a file name, use one of these three special characters as 
the first character of a string. The converter uses the rest of the string as a prompt. 

Character Prompt the user for... 

$ an existing directory 

# a new directory name 

? an existing file name 

For example, you can use this line to prompt for a folder: 

{$SETC IncludesDir = '$Which folder contains the include files? 1 } 

{$SKIP filename } 

Skip the specified file when processing the current directory. The file is not converted to the output 
directory. The $SKIP directive applies to the previous $ INPUT directive. 

{$USES unit name unitl unit2 ... } 

When the Pascal Source Converter encounters the unit <unit name>, it adds the specified units 
to the uses clause. The Pascal Source Converter takes care to avoid placing duplicate names in 
uses clauses. $USES applies to the next $ INPUT directive. 

A Sample Script 

Here is a small script that converts all the files in one directory. For a more complex scripts, see the 
file Generic . Script and MacApp. Script in the MacApp 2.0 for THINK Pascal 4.0 
Folder. 

{ Convert all the files in one directory } 

{$SETC InputDir = 1 $Which folder contains the original sources?'} 

{$SETC OutputDir = '#Name a folder for the converted sources.'} 
{$SETC IncludeDir = '$Which folder contains the include files?'} 

{$PORTABLE+} 

{$INCLUDES IncludeDir} 

{$OUTPUT OutputDir} 

{$INPUT InputDir} 


404 



Resource Description Files 

21 


Introduction 

This chapter describes resource description files, the files compiled by SARez and produced by 
SADeRez. See Chapters 22, “SARez,” and 23, “SADeRez,” for more information on these utilities. 
Complete background information on Macintosh resource files is given in the Inside Macintosh /, 
Chapter 5, “The Resource Manager,” and Inside Macintosh VI, Chapter 13, “The Resource 
Manager.” 

Both SARez and SADeRez started out life as tools in Apple’s Macintosh Programmer’s Workshop 
(MPW), where they were known as Rez and DeRez. MPW has a command-line interface, much like 
UNIX. At times it will seem these utilities work a bit oddly or have options you can’t use. This is be¬ 
cause of their heritage. But, despite their upbringing, they are still powerful and useful utilities. 

Topics covered in this chapter 

• The resource compiler and decompiler 

• Structure of a resource description file 

• Resource description statements 

• Labels 

• Preprocessor directives 

• Resource description syntax 


405 



THINK Pascal User Manual 


The Resource Compiler and Decompiler 

The resource compiler, SARez, compiles a text file (or files) called a resource description file 
and produces a resource file as output. The resource decompiler, SADeRez, decompiles an existing 
resource, producing a new resource description file that can be understood by SARez. This picture 
illustrates the complementary relationship between SARez and SADeRez. 


Resource 

file 


Resource Compiler 
(SARez) 


Resource Decompiler 
(SADeRez) 


Resource 

description 

file 

(TEXT) 


SARez can combine resources or resource descriptions from a number of files into a single resource 
file. SARez can also delete resources and change resource attributes. SARez has preprocessor 
directives that let you substitute macros, include other files, and use if-then-else constructs. (These 
directives are described under the heading “Preprocessor Directives” later in this chapter.) 

Resource decompiler 

SADeRez creates a textual representation of a resource file based on resource type declarations 
identical to those used by SARez. (If you don’t specify any type declarations, the output of 
SADeRez takes the form of raw data statements.) The output of SADeRez is a resource description 
file that may be used as input to SARez. This file can be edited in any text editor, so you can add 
comments, translate resource data to a foreign language, or specify conditional resource 
compilation with the if-then-else structures of the preprocessor. 


406 






Resource Description Files 21 


Standard type declaration files 

Three text files, Types. r, SysTypes. r, and Piet. r, contain resource declarations for standard 
resource types. These files are located in the {RIncludes} folder. 

File Contains... 

Types . r Type declarations for the most common Macintosh re¬ 

source types (* ALRT *, 'DITL 1 , * MENU \ and so on) 

SysTypes . r Type declarations for 1 DRVR 1 , * FOND ' , ' FONT * , 

* FWID 1 , 1 INTL 1 , 1 NFMT 1 , and many others 

Piet. r Type declaration for PICT resources for debugging 

PICTs 

Using SARez and SADeRez 

SARez and SADeRez are primarily used to create and modify resource files. This picture illustrates 
the process of creating a resource file. 



Structure of a Resource Description File 

The resource description file consists of resource type declarations (which can be included from 
another file) followed by resource data for the declared types. Note that the resource compiler and 


407 






THINK Pascal User Manual 


resource decompiler have no built-in resource types. You need to define your own types or 
include the appropriate . r files. 

A resource description file may contain any number of these statements: 


Statement 

include 

read 

data 

type 

resource 

change 

delete 


Description 

Include resources from another file. 

Read data fork of a file and include it as a resource. 

Specify raw data 

Type declaration — declare resource type descriptions for subsequent 
resource statements. 

Data specification — specify data for a resource type declared in a previous 
type statement. 

Change the type, ID, name, or attributes of existing resources. 

Delete existing resources. 


Each of these statements is described in the sections that follow. 


A type declaration describes how the declaration of a resource of that type will look like. You 
must declare a type (with a type statement) before you make a resource of that type (with a 
resource statement). Otherwise, you can freely mix type and resource statements in a file. 
You can redefine a type any number of times, even a type defined in Types . r, SysTypes. r, or 
Piet. r. 


A resource description file can also include comments and preprocessor directives: 

• Comments can be included any place white space is allowed in a resource description file, by 
putting them within the comment delimiters /* and */. Note that comments do not nest. For 
example, this is one comment: 

/* Hello /* there */ 

SARez also supports C++ style comments: 

type *tost' { // the rest of this line is ignored 

• Preprocessor directives substitute macro definitions and include files, and provide if-then- 
else processing before other SARez processing takes place. The syntax of the preprocessor is 
very similar to that of the C-language preprocessor. 


408 




Resource Description Files 


21 


Sample resource description file 

An easy way to learn about the resource description format is to decompile some existing re¬ 
sources. For example, using SADeRez to decompile an application’s resources might generate this: 

resource 'WIND* (128, "Sample Window") { 

{64, 60, 314, 460}, 
documentProc, 
visible, 
noGoAway, 

0x0, 

"Sample Window" 

} ; 


This resource data corresponds to the following type declaration, contained in Types. r: 
type 'WIND 1 { 


rect; 

/* 

boundsRect */ 

integer documentProc, dBoxProc, plainDBox, 
altDBoxProc, noGrowDocProc, 
zoomProc=8, rDocProc=16; 

/* 

procID */ 

byte invisible, visible; 

fill byte; 

/* 

visible */ 

byte noGoAway, goAway; 

fill byte; 

/* 

goAway */ 

unsigned hex longint; 

/* 

refCon */ 

pstring Untitled = "Untitled"; 

/* 

title */ 


Type and resource statements are explained in detail in the reference section that follows. The 
SADeRez utility is explained in detail in Chapter 23, “SADeRez.” 


Resource Description Statements 

This section describes the syntax and use of the seven types of resource description statements 
available for the resource compiler: include, read, data, type, delete, change, and 
resource. 


Syntax notation 

The following syntax notation is used to describe the resource description statements: 


terminal Plain text indicates a word that must appear in the statement exactly as shown. 

Special symbols (i.e., -, *, =) and punctuation (i.e., commas and semicolons 
must also be entered exactly as shown. 


nonterminal Items in italics can be replaced by anything that matches their definition. 
[ optional ] Square brackets mean that the enclosed elements are optional. 


409 


THINK Pascal User Manual 


repeated ... An ellipsis (...), when it appears in the text of this reference only ; indicates that 
the preceding item can be repeated one or more times. 

a I b A vertical bar indicates an either/or choice 

( grouping ) Parentheses indicate grouping (useful with the I and ... notation). 

‘ [’ x 1 ] ’ Curly single quotation marks (*...’) indicate that one of the syntax notation 

characters (for example, [ or 1) must be written as a literal. In this example, the 
brackets would be typed literally. They do not mean that the x is optional 

Spaces between syntax elements, constants, and punctuation are optional. They are shown for 
readability only. 

Tokens in resource description statements may be separated by spaces, tabs, returns, or comments. 

Special terms 

The following terms represent a minimal subset of the nonterminal symbols used to describe the 
syntax of commands in the resource description language: 


Term 

resource-type 

resource-name 

resource-ID 

ID-range 


Definition 

long-expression 

string 

word-expression 

IDUILA 


Note: Expression is defined later in this chapter under “Expressions.” 

A full syntax definition can be found at the end of this chapter. 

Include — Include resources from another file 

The include statement lets you read resources from an existing file and include all or some of 
them. 

Syntax 

An include statement can take the following forms: 

include file [ resource-type [*(’ resource-name \ ID [ :ID ] ‘)’] ] ; 

Read the resource of type resource-type with the specified resource name or resource ID range in 
file. If the resource name or ID is omitted, read all resources of the type resource-type in file. If 
resource-type is omitted, read all the resources in file. 

include file not resource-type ; 

Read all resources not of the type resource-type in file. 


410 



Resource Description Files 21 


include file resource-typel as resource-type2 ; 

Read all resources of type resource-typel and include them as resources of resource-type2. 

include file resource-typel ‘ (’ resource-name \ ID [ :ID ] V 

as resource-type2 ‘(’ZD [, resource-name ] [, attributes... ] 

Read the resource of type resource-typel with the specified name or ID range in fUe, and include it 
as a resource of resource-type2 with the specified ID. You can optionally specify a resource name 
and resource attributes. (Resource attributes are defined below.) 

Note; SADeRez ignores all include statements. 

Some examples follow: 

include "otherfile"; /* include all resources from the file */ 
include "otherfile" 'CODE'; /* read only the CODE resources */ 
include "otherfile" 'CODE' (128); /* read only CODE resource 128 */ 

AS resource description syntax 

The following string variables can be used in the as resource description to modify the resource 
information in include statements: 

$ $ Type Type of resource from include file 

$ $ ID ID of resource from include file 

$ $Name Name of resource from include file 

$ $Att ributes Attributes of resource from include file 

For example, to include all 1 DRVR 1 resources from one file and keep the same information but 
also set the SYSHEAP attribute: 

INCLUDE "file" 'DRVR' (0:40) AS 

'DRVR' ($$ID, $$Name, $$Attributes | 64) ; 

The $$Type, $$ID, $$Name, and $$ At tributes variables are also set and legal within a 
normal resource statement. At any other time the values of these variables are undefined. 

Resource attributes 

You can specify attributes as a numeric expression (as described in Inside Macintosh /, Chapter 5, 
“The Resource Manager,” and Inside Macintosh VI, Chapter 13, “The Resource Manager”), or you 
can set them individually by specifying one of the keywords from any of the following pairs: 

Default Alternative Meaning 

appheap sysheap Specifies whether the resource is to be loaded 

into the application heap or the system heap. 

nonpurgeable purgeable Purgeable resources can be automatically purged 

by the Memory Manager. 


411 



THINK Pascal User Manual 


Default 

unlocked 

Alternative 

locked 

Meaning 

Locked resources cannot be moved by the 

Memory Manager. 

unprotected 

protected 

Protected resources cannot be modified by the 

Resource Manager. 

nonpreload 

preload 

Preloaded resources are placed in the heap as 
soon as the Resource Manager opens the resource 
file. 

unchanged 

changed 

Tells the Resource Manager whether a resource 
has been changed. SARez does not allow you to 
set this bit, but SADeRez will display it if it is set 


Bits 0 and 7 of the resource attributes are reserved for use by the Resource Manager and cannot be 
set by SARez, but are displayed by SADeRez. 

You can specify more than one attribute by separating the keywords with a comma (,). 

Read — read data as a resource 

The read statement lets you read a file’s data fork as a resource. 

Syntax 

read resource-type ‘(’ ID [, resource-name ] [, attributes] l ) ’ file ; 

Description 

Reads the data fork from file and writes it as a resource with the type resource-type and the re¬ 
source ID ZD, with the optional resource name resource-name and optional resource attributes (as 
defined in the preceding section). For example, 

read 'STR ' (-789,"Test String",SysHeap,PreLoad) "Test8"; 

Note: SADeRez ignores all read statements. 

Data — specify raw data 

Use the data statement to specify raw data as a sequence of bits, without any formatting. 

Syntax 

data resource-type ‘ (’ ID [, resource-name ] [, attributes ... ] ‘) ’ V 

data-string 

V; 

Description 

Reads the data found in data-string and writes it as a resource with the type resource-type and the 
ID ID. You can optionally specify a resource name, resource attributes, or both. 


412 



Resource Description Files 


21 


For example, 

data * PICT 1 (128) { 

$"4F35FF8790000000" 

$"FF234F35FF790000" 

); 

Note: When SADeRez generates a resource description, it uses the data state¬ 
ment to represent any resource type that doesn’t have a corresponding type dec¬ 
laration or cannot be disassembled for some other reason. SADeRez ignores any 
data statements in the resource description files you provide. 

Type — declare resource type 

A type declaration provides a template that defines the structure of the resource data for a single 
resource type or for individual resources. If more than one type declaration is given for a resource 
type, the last one read before the data definition is the one that’s used. This lets you override 
declarations from include files or previous resource description files. 

Syntax 

type resource-type [ ‘(’ ID-range ‘) ’ ] *{’ 

type-specification ... 

T ; 

Description 

Causes any subsequent resource statement for the type resource-type to use the declaration { type- 
specification. .. ). The optional ID-range specification causes the declaration to apply only to a 
given resource ID or range of IDs. 

Type-specification is one of the following: 

bitstring[n] 
byte 
integer 
longint 
boolean 
char 
string 
pstring 
wstring 
cstring 
point 
rect 
fill 
align 
switch 
array 


Zero fill 

Zero fill to nibble, byte, word, or long word boundary 
Control construct (case statement) 

Array data specification—zero or more instances of data types 


413 



THINK Pascal User Manual 


These types can be used singly or together in a type statement. Each of these type specifiers is 
described in the sections that follow. 

Note: Several of these types require additional fields. The exact syntax is given in 
the sections that follow. 

You can also declare a resource type that uses another resource’s type declaration by using the 
following variant of the type statement: 

type resource-typel [ ‘(’ ID-range V ] as resource-type2 [*(* ID *)’]; 

Data type specifications 

A Data-type statement declares a field of the given data type. It can also associate symbolic names 
or constant values with the data type. The data-type specification can take three forms, as shown 
in this example: 

type 'XAMP' { /* declare a resource of type 'XAMP' */ 

byte; 

byte off=0, on=l; 
byte = 2; 

}; 


• The first byte statement declares a byte field; the actual data is supplied in a subsequent 
resource statement. 

• The second byte statement is identical to the first, except that the two symbolic names off 
and on are associated with the values 0 and 1. These symbolic names could be used in the 
resource data. 

• The third byte statement declares a byte field whose value is always 2. In this case, no 
corresponding statement would appear in the resource data. 

Numeric expressions and strings can appear in type statements; they are defined later in this 

chapter under “Expressions.” 

Numeric types: The numeric types (bitstring, byte, integer, longint) are fully specified 

like this: 

[ unsigned ] [ radix ] numeric-type [ =expr \ symbol-definition... ] ; 

• The unsigned prefix signals SADeRez that the number should be displayed without a sign— 
that the high-order bit can be used for data and the value of the integer cannot be negative. The 
unsigned prefix is ignored by SARez but is needed by SADeRez to correctly represent a 
decompiled number. SARez uses a sign if it is specified in the data. Precede a signed negative 
constant with a minus sign (-); $FFFFFF85 and - $7B are equivalent in value. 

• Radix is one of the following string constants: 

hex decimal octal binary literal 

You can supply numeric data as decimal, octal, hexadecimal, or literal data. 



Resource Description Files 21 


• Numeric-type is one of the following: 

bit st ring T length T Declare a bitstring of length bits (maximum 32).. 

byte Declare a byte (8-bit) field. This is the same as 

bitstring[8]. 

integer Integer (l6-bit) field. This is the same as 

bitstring[16]. 

longint Long integer (32-bit) field. This is the same as 

bitstring[32] 

SARez uses integer arithmetic and stores numeric values as integer numbers. SARez translates 
booleans, bytes, integers, and longints to bitstring equivalents. All computations are done in 32 bits 
and truncated. 

An error is generated if a value won’t fit in the number of bits defined for the type. The valid ranges 
for values of byte, integer, and longint constants are as follows: 

Type Maximum Minimum 

byte 255 -128 

integer 65,535 -32,768 

longint 4,294,967,295 -2,147,483,648 

Boolean type: A Boolean is a single bit with two possible states: 0 (or false) and 1 (or true). 
(True and false are global predefined identifiers.) Boolean values are declared as follows: 

boolean [ = constant \ symbolic-value... ]; 

The type boolean declares a 1-bit field; this is equivalent to 

unsigned bitstring[1] 

Note: This type is not the same as a Boolean variable as defined by Pascal. 

Character type: Characters are declared as follows: 

char [ = string \ symbolic-value... ] ; 

Type char declares an 8-bit field (this is the same as writing string [ 1 ]). 

Here is an example: 

type 'SYMB' { 

char dollar = percent = 

}; 

resource 'SYMB' (128) { 

dollar 

}; 


415 



THINK Pascal User Manual 


String type: String data types are specified like this: 
string-type [T length ‘]’] [= string I symbol-value...] ; 

String-type is one of the following: 

Type Description 

[hex] string Plain string (no length indicator or termination charac¬ 

ter is generated). The optional hex prefix tells 
SADeRez to display it as a hex string. String [ n] con¬ 
tains n characters and is n bytes long. The type char 
is shorthand for String [ 1 ]. 

Pascal string (a leading byte containing the length in¬ 
formation is generated). Pst ring [ n] contains n 
characters and is n+1 bytes long. Pst ring has a built- 
in maximum length of 255 characters, the highest value 
the length byte can hold. If the string is too long to fit 
the field, a warning is given and the string is truncated. 

Word string is a very large pst ring. Its length is 
stored in the first two bytes. Therefore, a word string 
can contain up to 65,535 characters. Wstring[n] 
contains n characters and is n+2 bytes long. 

C string (a trailing null byte is generated). 
cstring[n] contains n- 1 characters and is n bytes 
long. A C string of length 1 can be assigned only the 
value "”, because cstring [ 1 ] has room only for the 
terminating null. 

Each string type may be followed by an optional length indicator in brackets ([ n ]). Length is an 
expression indicating the string length in bytes. Length is a positive number in the range 
1 < length < 2147483647 for string and cst ring, and in the range 1 < length < 255 for 
pstring, and in the range 1 < length < 65535 forwstring. 

Note: You cannot assign the value of a literal to a string type. 

If no length indicator is given, a pstring, wstring, or cst ring stores the number of charac¬ 
ters in the corresponding data definition. If a length indicator is given, the data may be truncated 
on the right or padded on the right. The padding characters for all string types are nulls. If the data 
contains more characters than the length indicator provides for, the string is truncated and a 
warning message is given. 

Warning: A null byte within a cst ring is a termination indicator and may con¬ 
fuse SADeRez and C programs. However, the full string, including the explicit null 
and any text that follows it, will be stored by SARez as input. 


pstring 


wstring 


cstring 


416 



Resource Description Files 


21 


Resource description statements :Point and rectangle types: Because points and rectangles appear so 
frequently in resource files, they have their own simplified syntax: 

point [ = point-constant | symbolic-value... ] ; 
rect [ = rect-constant \ symbolic-value... ] ; 

where 

point-constant = *{’ x-integer-expr,y-integer-expr 


and 

rect-constant = 1 { 1 integer-expr, integer-expr , integer-expr , integer-expr 1 } ’ 

These type statements declare a point (two 16-bit signed integers) or a rectangle (four 1 6 -bit signed 
integers). The integers in a rectangle definition specify the rectangle’s upper-left and lower-right 
points, respectively. 

Fill and align types 

The resource created by a resource definition has no implicit alignment. It’s treated as a bit stream, 
and integers and strings can start at any bit. The fill and align type specifiers are two ways of 
padding fields so that they begin on a boundary that corresponds to the field type. Align is 
automatic and fill is explicit. Both fill and align generate zero-filled fields. 

Fill specification: The fill statement causes SARez to add the specified number of bits to the 
data stream. The fill is always 0. The form of the statement is 

fill fill-size [ *[’ length ']’ ] ; 

where fill-size is one of the following strings: 

bit nibble byte word long 

These declare a fill of 1, 4, 8, 16 , or 32 bits (optionally multiplied by the length modifier). Length is 
an expression < 2147483647. 

The following fill statements are equivalent: 

fill word[2]; 
fill long; 
fill bit[32]; 

The full form of a type statement specifying a fill might be: 

type 1 XRES 1 { data-type specifications ; fill bit [2];}; 

Note: SARez supplies zeros as specified by fill and align statements. 

SADeRez does not supply any values for fill or align statements; it just skips 
the specified number of bits, or until data is aligned as specified. 




THINK Pascal User Manual 


Align specification; Alignment causes SARez to add fill bits of zero value until the data is aligned 
at the specified boundary. An alignment statement takes the following form: 

align align-size ; 

where align-size is one of these strings: 

nibble byte word long 

Alignment pads with zeros until data is aligned on a 4-, 8-, 1 6 -, or 32-bit boundary. This alignment 
affects all data from the point where it is specified until the next align statement. 

Array type 

An array is declared as follows: 

[ wide ] array [ array-name I *[’ length '] ’ ] *{’ array-list ‘1’; 

The array-list , a list of type specifications, is repeated zero or more times. The wide option outputs 
the array data in a wide display format (in SADeRez)—the elements that make up the array-list are 
separated by a comma and space instead of a comma, return, and tab. Either array-name or 
[ length ] may be specified. Array-name is an identifier. 

If the array is named, then a preceding statement should refer to that array in a constant expression 
with the $$ Count Of (array-name) function; otherwise SADeRez will treat the array as an open- 
ended array. For example, 

type 'STR#' { /* define a string list resource */ 

integer = $$Countof(StringArray); 
array StringArray { 
pstring; 

1; 

}; 


The $$CountOf function returns the number of array elements (in this case, the number of 
strings) from the resource data. 

If [ length ] is specified, there must be exactly length elements. 

Array elements are generated by commas. Commas are element separators. Semicolons are element 
terminators. In this example, however, it may be a good idea to use semicolons as element 
separators: 

type *xyzy' { 

array Increment { 

integer = $$ArrayIndex(Increment); 

1; 

}; 


418 



Resource Description Files 


21 


resource *xyzy' (0) { 

{ /* zero elements */ 

} 

}; 

resource 'xyzy' (1) { 

{ /* two elements */ 

r 

} 

}; 

resource 'xyzy' (3) { 

} /* two elements */ 

} 

}; 

/* The only way to specify one element in an array that has all 
constant elements, is to use a semicolon terminator. 

*/ 

resource 'xyzy* (4) { 

{ /* one element */ 

f 

) 

}; 

Switch type 

The switch statement specifies a number of case statements for a given field or fields in the 
resource. The format is: 

switch ‘{’ case-statement... V; 

where a case-statement has this form: 

case case-name : [ case-body ; ]... 

Case-name is an identifier. Case-body may contain any number of type specifications and must 
include a single constant declaration per case, in this form: 

key data-type = constant 


419 



THINK Pascal User Manual 


Which case applies is based on the key value. For example, 


type 


1 DITL 1 { /* dialog item list declaration from Types.r 


... type specifications ... 
switch { 
case Button: 

boolean enabled, 
key bitstring[7] 
pstring; 
case CheckBox: 

boolean enabled, 
key bitstring[7] 
pstring; 

...andso on. 


/* one of the following */ 
disabled; 

=4; /* key value */ 


disabled; 

=5; /* key value */ 


*/ 


1; 


1; 


Sample type statement 

The following sample type statement is the standard declaration for a 'WIND ' resource, taken 
from the Types . r file: 


type 'WIND 1 { 


rect ; 

/* 

bounds 

*/ 

integer documentProc, dBoxProc, plainDBox, 
altDBoxProc, noGrowDocProc, 
zoomProc=8, rDocProc=16; 

/* 

procID 

*/ 

byte invisible, visible; 

fill byte; 

/* 

visible 

*/ 

byte noGoAway, goAway; 

fill byte; 

/* 

close box 

*/ 

unsigned hex longint; 

/* 

refCon 

*/ 

pstring Untitled = "Untitled"; 

/* 

title 

*/ 


1; 


The type declaration consists of header information followed by a series of statements, each 
terminated by a semicolon (;). The header of the sample window declaration is 

type 'WIND' 

The header begins with the Type keyword followed by the name of the resource type being de¬ 
clared—in this case, a window. You may specify a standard Macintosh resource type, as shown in 
the Inside Macintosh /, Chapter 5, “The Resource Manager," and Inside Macintosh VI, Chapter 13, 
“The Resource Manager," or you may declare a resource type specific to your application. 

The left brace [ {1 introduces the body of the declaration. The declaration continues for as many 
lines as necessary until a matching right brace} is encountered. You can write more than one 
statement on a line, and a statement may be on more than one line (like the integer statement 
above). Each statement represents a field in the resource data. Recall that comments may appear 


420 



Resource Description Files 


21 


anywhere where white space may appear in the resource description file; comments begin with / * 
and end with * / as in C. 

Symbol definitions 

Symbolic names for data type fields simplify the reading and writing of resource definitions. 

Symbol definitions have the form 

name = value [, name = value ]... 

For numeric data, the “= valuer part of the statement can be omitted. If a sequence of values con¬ 
sists of consecutive numbers, the explicit assignment can be left out—if value is omitted, it’s as¬ 
sumed to be one greater than the previous value. (The value is assumed to be zero if it’s the first 
value in the list.) This is true for bitstrings (and their derivatives, byte, integer, and longint). 
For example, 

integer documentProc f dBoxProc, plainDBox, 
altDBoxProc, noGrowDocProc, 
zoomProc=8, rDocProc=16; 

In this example, the symbolic names documentProc, dBoxProc, plainDBox, altDBoxProc, 
and noGrowDocProc are automatically assigned the numeric values 0, 1, 2, 3, and 4. 

Memory is the only limit to the number of symbolic values that can be declared for a single field. 
There is also no limit to the number of names you can assign to a given value; for example, 

integer documentProc=0, dBoxProc=l, plainDBox=2 f altDBoxProc=3, 
rDocProc=16, Document=0, Dialog=l, DialogNoShadow=2, 
ModelessDialog=3, DeskAccessory=l6; 

Delete — delete a resource 

Sometimes you may want to delete a resource without switching to ResEdit. Some resource opera¬ 
tions, such as those needed by “internationalizing” system disks and applications need to translate 
menu and dialog text, and hence require deleting or changing resources. 

Syntax 

delete resource-type ['(’ resource-name \ ID[:ID ] ‘) ’] ; 

Description 

Delete the resource of type resource-type from the output file with the specified resource name or 
resource ID range. If the resource name or ID is omitted, all resources of type resource-type are 
deleted. 


Note: The delete function is valid only when you are appending to an existing 
file. It makes no sense to delete resources while creating a new resource file from 
scratch. Also, SADeRez ignores all delete commands. 


421 



THINK Pascal User Manual 


You can delete resources that have their protected bit set only if you select the OK to Replace 
Protected Resources option in SARez. 

Change — change a resource’s vital Information 

You can change a resource’s vital information by using this function. Vital information includes the 
resource type, ID, name, attributes, or any combination of these at once. 

Syntax 

change resource-typel [ ‘(’ resource-name | ID[:ID] *)’ ] 

to resource-type 2 ‘(’ ID [, resource-name ] [, attributes...] *)*; 

Description 

Change the resource of type resource-typel from the output file with the specified resource name 
or resource ID range to a resource of type resource-type2 with the specified ID. You can optionally 
specify a resource name and resource attributes. If the resource name or attributes are not 
specified, the name and attributes are not changed. 

For example, this statement sets the protected bit on all code resources: 

change 'CODE* to $$type ($$ID,$$Attributes | 8); 

Note: The change function is only valid when you are appending to an existing 
file. It makes no sense to change resources while creating a new resource file 
from scratch. Also, SADeRez ignores all change commands. 

Resource — specify resource data 

Resource statements specify actual resources, based on previous type declarations. 

Syntax 

resource resource-type 1 (’ ID [, resource-name ] [, attributes] *)’ 

[ data-statement [ , data-statement ]... 1 
T; 

Description 

Specifies the data for a resource of type resource-type and ID ID. The latest type declaration de¬ 
clared for resource-type is used to parse the data specification. Data-statements specify the actual 
data; data-statements appropriate to each resource type are defined in the next section. 

The resource definition causes an actual resource to be generated. A resource statement can 
appear anywhere in the resource description file, or even in a separate file specified on the 
command line or as an #include file, as long as it comes after the relevant type declaration. 

Note: SADeRez ignores all resource statements. 


422 



Resource Description Files 


21 


Data statements 

The body of the data specification contains one data statement for each declaration in the 
corresponding type declaration. The base type must match the declaration. 

Base type Instance types 

string string, cstring, pstring, wstring, char 

bitstring boolean, byte, integer, longint, bitstring 

rect rect 

point point 

Switch data: Switch data statements are specified by using this format: 
switch-name data-hody 

For example, the following could be specified for the 1 ditl 1 type given earlier: 


CheckBox { enabled, "Check here" }, 

Array data: Array data statements have this format: 

‘ {’ [ array-element [ , array-element ]... 1 ‘ 1 ’ 

where an array-element consists of any number of data statements separated by commas. 

For example, the following data might be given for the ' STR# ' resource defined earlier: 

resource 'STR#' (280) { 

{ "this", 

"is", 

IV -> IV 
d f 

"test" 



Sample resource definition 

This section describes a sample resource description file for a window. (See the chapter Inside 
Macintosh /, Chapter 9,“Window Manager,” and Inside Macintosh IV, Chapter 6, “The Window 
Manager,” for information about resources in windows.) 


423 



THINK Pascal User Manual 


Here, again, is the type declaration given above under “Sample Type Statement”: 
type 'WIND'{ 


rect ; 

/* 

bounds 

*/ 

integer documentProc, dBoxProc, plainDBox, 
altDBoxProc, noGrowDocProc, 
zoomProc=8, rDocProc=16; 

/* 

procID 

*/ 

byte invisible, visible; 
fill byte; 

/* 

visible 

*/ 

byte noGoAway, goAway; 
fill byte; 

/* 

close box 

*/ 

unsigned hex longint; 

/* 

refCon 

*/ 

pstring Untitled = "Untitled"; 

/* 

title 

*/ 


}; 

Here is a typical example of the window data corresponding to this declaration: 
resource 'WIND' (128, H My window",appheap,preload) { 



/* 

Status report window 

*/ 

{40,80,120,300}, 

/* 

Bounding rectangle 

*/ 

documentProc, 

/* 

documentProc etc.. 

*/ 

Visible, 

/* 

Visible or Invisible 

*/ 

goAway, 

/* 

GoAway or NoGoAway 

*/ 

0, 

/* 

Reference value RefCon 

*/ 

"Status Report" 

/* 

Title 

*/ 


}; 


This data definition declares a resource of type ' WIND', using whatever type declaration was pre¬ 
viously specified for 'WIND '. The resource ID is 128; the resource name is My window. Because 
the resource name is represented by the Resource Manager as a pstring, it should not contain 
more than 255 characters. The resource name may contain any character including the null charac¬ 
ter ($00). The resource will be placed in the application heap when loaded, and it will be loaded 
when the resource file is opened. 

The first statement in the window type declaration declares a bounding rectangle for the window: 
rect ; 

The rectangle is described by two points: the upper-left corner and the lower-right corner. The 
points of a rectangle are separated by commas like this: 

{ top, left, bottom, right } 

An example of data for these coordinates is 

{40,80,120,300} 


424 



Resource Description Files 


21 


Symbolic names: Symbolic names may be associated with particular values of a numeric type. 
Notice that a symbolic name is given for the data in the second, third, and fourth fields of the 
window declaration. For example, 

integer documentProc=0, dBoxProc=l, plainDBox=2, 
altDBoxProc=3, noGrowDocProc=4, 
zoomProc=8, rDocProc=16; /* windowType */ 

This statement specifies a signed 16-bit integer field with symbolic names associated with the val¬ 
ues 0 to 4 and 16. The values 0 through 4 need not be indicated in this case; if no values are given, 
symbolic names are automatically given values starting at 0, as explained previously. 

In the sample window declaration, we gave the values True (1) and False (0) to two different 
byte variables. For clarity, we used those symbolic names in the window’s resource data; that is, 

visible, 

goAway, 

instead of their equivalents 
TRUE, 

TRUE, 


1 , 

1 , 


Labels 

Labels support some of the more complicated resources such as ' NFNT ' and color QuickDraw re¬ 
sources. Use labels within a resource type declaration to calculate offsets and permit accessing of 
data at the labels. 

Syntax 

label 
character 
number 
alphanum 

Description 

Labeled statements are valid only within a resource type declaration. Labels are local to each type 
declaration. More than one label can appear on a statement. 

Labels may be used in expressions. In expressions, use only the identifier portion of the label (that 
is, everything up to, but excluding, the colon). See “Declaring Labels Within Arrays” later in this 
chapter for more information. 


= character {alphanum}* 

= | A | B | C ... 

-0|1|2|3|4|5|6|7|8|9 
= character | number 


425 





THINK Pascal User Manual 


The value of a label is always the offset, in bits , between the beginning of the resource and the 
position where the label occurs when mapped to the resource data. In this example, 

type 'cool' { 
cstring; 
endOfString: 

integer = endOfString; 

) ; 


resource 'cool' (8) { 

"Neato" 

} 

the integer following the cstring would contain: 

( len ( "Neato”) [5] + null byte [1] ) * 8 [bits per byte] = 48. 

Built-in functions to access resource data 

In some cases, it is desirable to access the actual resource data that a label points to. Several built- 
in functions allow access to that data: 

$$BitField( label, startingPosition, numberOfBits) 

Returns the numberOfBits (maximum of 32) bitstring found startingPosition bits from label. 
$$Byte (label) 

Returns the byte found at label. 

$ $w or d (label) 

Returns the word found at label. 

$$Long (label) 

Returns the longword found at label. 

For example, the resource type ' STR ' could be redefined without using a pst ring. Here is the 
definition of 1 STR' from Types . r: 

type 'STR' { 
pstring; 

1 

Here is a redefinition of 'STR ' using labels: 
type 'STR ' { 

len: byte = (stop - len) / 8 - 1; 

string[$$Byte(len)]; 
stop: 

) ; 


426 



Resource Description Files 


21 


Declaring labels within arrays 

Labels declared within arrays may have many values. For every element in the array, there is a cor¬ 
responding value for each label defined within the array. Use array subscripts to access the individ¬ 
ual values of these labels. The subscript values range from 1 to n where n is the number of ele¬ 
ments in the array. Labels within arrays that are nested in other arrays require multidimensional 
subscripts. Each level of nesting adds another subscript. The rightmost subscript varies most 
quickly. Here is an example: 

type 'test 1 { 

integer = $$CountOf(arrayl); 
array arrayl { 

integer = $$CountOf(array2); 
array array2 { 
foo: integer; 

}; 



resource 'test' (128) { 

{ 

(1,2,3), 

(4,5) 



In the above example, the 

label foo takes on these values: 

foo[l,l] = 32 

$$Word(foo[1,1] 

) 

= 1 

foo[l,2] = 48 

$$Word(foo[1,2] 

) 

= 2 

food,3] = 64 

$$Word(foo[1,3]) 

= 3 

foo[2,1] = 96 

$$Word(foo[2,1] 

) 

= 4 

foo[2,2] = 112 

$$Word(foo[2,2] 

) 

= 5 


A new built-in function may be helpful in using labels within arrays: 

$$Ar ray Index ( arrayname) 

This function returns the current array index of the array arrayname. An error occurs if this 
function is used anywhere outside the scope of the array arrayname. 

Label limitations 

Keep in mind the fact that SARez and SADeRez are basically one-pass compilers. This will help you 
understand some of the limitations of labels. 

Note: To decompile (or “DeRez”) a given type, that type must not contain any 
expressions with more than one undefined label. An undefined label is a label 
that occurs lexically after the expression. To define a label, use it in an expression 
before the label is defined. 


427 



THINK Pascal User Manual 


This example demonstrates how expressions can only have only one undefined label: 
type 'test' { 

/* In the expression below, start is defined, next is undefined.*/ 
start: integer = next - start; 

/* In the expression below, next is defined because it was used 
in a previous expression, but final is undefined.*/ 
middle: integer = final - next; 
next: integer; 

final: 

}; 

Actually, SARez can compile types that have expressions containing more than one undefined la¬ 
bel, but SADeRez cannot decompile those resources and simply generates data resource 
statements. 

Note: The label specified in $$BitField (), $$Byte (), $$Word (), and 
$$Long () must occur lexically before the expression; otherwise, an error is gen¬ 
erated. 


428 




Resource Description Files 


21 


Using labels: two examples 

The first example shows the modified ' ppat' declaration using the new SARez labels. Boldface 
text in the example indicates everything that is different between the 2.0 and 3.0 versions of 
' ppat' because of the use of labels. Without using labels, the whole end section of the resource 
would have to be combined into a single hex string (everything following the PixelData label). 
Using labels, the complete ' ppat 1 definition can be expressed in SARez language. 

type 'ppat' { 

/* PixPat record */ 


integer oldPattern, 

/* Pattern type 

*/ 

newPattern, 



ditherPattern; 



unsigned longint = PixMap / 8; 

/* Offset to pixmap 

*/ 

unsigned longint = PixelData/8 

; /* Offset to data 

*/ 

fill long; 

/* Expanded pixel image 

*/ 

fill word; 

/* Pattern valid flag 

*/ 

fill long; 

/* expanded pattern 

* / 

hex string [8] ; 

/* old-style pattern 

*/ 


/* PixMap record 

*/ 

PixMap: 



fill long; 

/* Base address 

*/ 

unsigned bitstring[1] = 1; 

/* New pixMap flag 

*/ 

unsigned bitstring[2] = 0; 

/* Must be 0 

*/ 

unsigned bitstring[13]; 

/* Offset to next row 

*/ 

rect ; 

/* Bitmap bounds 

*/ 

integer; 

/* pixMap vers number 

*/ 

integer unpacked; 

/* Packing format 

*/ 

unsigned longint; 

/* size of pixel data 

*/ 

unsigned hex longint; 

/* h. resolution (ppi) (fixed) 

*/ 

unsigned hex longint; 

/* v. resolution (ppi) (fixed) 

*/ 

integer chunky, chunkyPlanar, 

planar;/* Pixel storage format 

*/ 

integer; 

/* # bits in pixel 

*/ 

integer; 

/* # components in pixel 

*/ 

integer; 

/* # bits per field 

*/ 

unsigned longint; 

/* Offset to next plane 

*/ 

unsigned longint = ColorTable 

/ 8; /* Offset to color table 

*/ 

fill long; 

/* Reserved 

*/ 


PixelData: 

hex string [(ColorTable - PixelData) / 8]; 


429 


THINK Pascal User Manual 


ColorTable: 


unsigned hex longint; 

/* ctSeed 

*/ 

integer; 

/* transindex 

*/ 

integer = $$Countof(ColorSpec) 
wide array ColorSpec { 

- 1; /* ctSize 

*/ 

integer; 

/* value 

*/ 

unsigned integer; 

/* RGB: red 

*/ 

unsigned integer; 

/* green 

*/ 

unsigned integer; 

/* blue 

*/ 


); 

}; 

Here is another example of a new resource definition with the new features in bold. In this exam¬ 
ple, the $$BitField() function is used to access information stored in the resource, in order to 
calculate the size of the various data areas added at the end of the resource. Without labels, all 
data would have to be combined into one hex string. 


type 1 cicn' { 

fill long; 

unsigned bitstring[1] = 1; 
unsigned bitstring[2] = 0; 
pMapRowBytes : unsigned bitstring[13]; 
Bounds :rect; 
integer; 

integer unpacked; 

unsigned longint; 

unsigned hex longint; 

unsigned hex longint; 

integer chunky, chunkyPlanar, pla 

integer; 

integer- 

integer; 

unsigned longint; 
unsigned longint; 
fill long; 

fill long; 

maskRowBytes : integer; 
rect ; 


fill long; 

IconBMapRowBytes : integer; 
rect; 

fill long; 


/* IconPMap (pixMap) record */ 
/* Base address */ 

/* New pixMap flag */ 

/* Must be 0 */ 

/* Offset to next row */ 

/* Bitmap bounds */ 

/* pixMap vers number */ 

/* Packing format */ 

/* Size of pixel data */ 

/* h. resolution (ppi) (fixed)*/ 
/* v. resolution (ppi) (fixed)*/ 
r; /* Pixel storage format */ 
/* # bits in pixel */ 

/* # components in pixel */ 
/* # bits per field */ 

/* Offset to next plane */ 

/* Offset to color table */ 
/* Reserved */ 

/* IconMask (bitMap) record */ 
/* Base address */ 

/* Row bytes */ 

/* Bitmap bounds */ 

/* IconBMap (bitMap) record */ 
/* Base address */ 

/* Row bytes */ 

/* Bitmap bounds */ 

/* Handle placeholder */ 


430 



Resource Description Files 


21 


/* Mask data */ 

hex string [$$Word(maskRowBytes) * ($$BitField(Bounds, 32, 16) 
/★bottom*/ 

- $$BitField(Bounds, 0, 16) /*top*/)]; 

/* BitMap data */ 

hex string [$$Word(iconBMapRowBytes) * 

($$BitField(Bounds, 32, 16)/*bottom*/ 

- $$BitField(Bounds, 0, 16) /* top */)]; 


/* Color Table */ 


unsigned hex longint; 

/* 

ctSeed 

*/ 

integer; 

/* 

transindex 

integer = $$Countof(ColorSpec) 
wide array ColorSpec { 

- 1; /* 

ctSize 

*/ 

integer; 

/* 

value 

*/ 

unsigned integer; 

/* 

RGB: red 

*/ 

unsigned integer; 

/* 

green 

*/ 

unsigned integer; 

/* 

blue */ 



); 


/* PixelMap data */ 

hex string [$$BitField(pMapRowBytes,0,13) * 

($$BitField(Bounds, 32,16) /* bottom */ 

- $$BitField(Bounds, 0, 16) /*top*/)]; 

>; 

Preprocessor Directives 

Preprocessor directives substitute macro definitions and include files and provide 
if-then-else processing before other SARez processing takes place. 

The syntax of the preprocessor is very similar to that of the C-language preprocessor. Preprocessor 
directives must observe these rules and restrictions: 

• Each preprocessor statement must be expressed on a single line, beginning on a new 
line and terminated by a return character. 

• The pound sign ( # ) must be the first character on the line of the preprocessor 
statement (except for spaces and tabs). 

• Identifiers (used in macro names) may be letters (A-Z, a-z), digits (0-9), or the 
underscore character ( _ ). 

• Identifiers may be any length. 

• Identifiers may not start with a digit. 

• Identifiers are not case sensitive. 


431 



THINK Pascal User Manual 


Variable definitions 

The #define and #undef directives let you assign values to identifiers: 

#def ine macro data 
#undef macro 

The #def ine directive causes any occurrence of the identifier macro to be replaced with the text 
data. You can extend a macro over several lines by ending the line with the backslash character 
(\), which functions as the SARez escape character. For example, 

#define poem "I wander \ 
thro\' each \ 
charter\'d street” 

(Quotation marks within strings must also be escaped.) 

#undef removes the previously defined identifier macro. Macro can also be defined and 
undefined in the Preprocessor... dialog in SARez or in the Preprocessor box in SADeRez. 

The following predefined macros are provided: 


Variable 

Value 



true 

1 



false 

0 



rez 

1 or 0 

(1 if SARez is running, 

0 if SADeRez is running) 

derez 

1 or 0 

(0 if SARez is running, 

1 if SADeRez is running) 


Include directives 

The #include directive reads a text file: 

#include file 

Include the text file file. The maximum nesting is to ten levels. For example, 

#include "MyTypes.r” 

Note that the #include preprocessor directive (which includes a file) is different from the 
previously described include statement, which copies resources from another file. 

If-Then-Else processing 

These directives provide conditional processing: 

#if expression 
[ #elif expression ] 

T #else ] 

#endif 



Resource Description Files 


21 


Note: Expression is defined later in this chapter. When used with the # i f and 
#elif directives, expression may also include this expression: 
defined identifier on defined '('identifier 1 )' 

The following may also be used in place of #if: 

#ifdef macro 
#ifndef macro 

For example, 

#define Thai 

Resource 'STR ' (199) { 

#ifdef English 
"Hello” 

#elif defined (French) 

"Bonjour” 

#elif defined (Thai) 

"Sawati” 

#elif defined (Japanese) 

"Konnichiwa” 

#endif 

}; 


Print directive 

The #print f directive is provided to aid in debugging resource description files: 

#printf (formatstring, arguments...) 

The format of the #printf statement is exactly the same as the print f statement in the C lan¬ 
guage, with one exception: There can be no more than 20 arguments. This is the same restriction 
that applies to the $$format function. The #printf directive writes its output to diagnostic 
output. Note that the #printf directive does note nd with a semicolon. 

Note: SARez and SADeRez will not print the results of the #printf directive if 
you do not select an error file or if there are no errors. (SARez and SADeRez don’t 
print error files if there are no errors to report.) 

For example: 

#define Tuesday 3 
#ifdef Monday 

#printf(”The day is Monday, day #%d\n", Monday) 

#elif defined(Tuesday) 

#printf("The day is Tuesday, day #%d\n", Tuesday) 

#elif defined(Wednesday) 

#printf("The day is Wednesday, day #%d\n", Wednesday) 

#elif defined(Thursday) 

#printf("The day is Thursday, day #%d\n", Thursday) 


433 



THINK Pascal User Manual 


#else 

#printf("DON'T KNOW WHAT DAY IT IS!\n") 

#endif 

The above file generates this text: 

The day is Tuesday, day #3 

Resource Description Syntax 

This section describes the details of the resource description syntax. 

Numbers and literals 

All arithmetic is performed as 32-bit signed arithmetic. The basic constants are shown below: 


Numeric type 

Form 

Meaning 

Decimal 

nnn... 

Signed decimal constant between 4,294,967,295 and 
-2,147,483,648. 

Hex 

OXhhh... 

Signed hexadecimal constant between 0X7FFFFFFF and 
0X80000000. 


$ hhh... 

Alternate form for hexadecimal constants. 

Octal 

0 ooo... 

Signed octal constant between 017777777777 and 
020000000000. 

Binary 

Ob bbb... 

Signed binary constant between 
0B11111111111111111111111111111111and 
0B10000000000000000000000000000000. 

Literal 

' aaaa' 

A literal may contain one to four characters. Characters are 
printable ASCII characters or escape characters. If there are 
fewer than four characters in the literal, then the characters 
to the left (high bits) are assumed to be $00. Characters 
that are not in the printable character set, and are not the 
characters \ ' and \ \ (which have special meanings), can 
be escaped according to the character escape rules. (See 
“Strings” later in this section.) 


Literals and numbers are treated in the same way by the resource compiler. A literal is a value 
within single quotation marks; for instance, ' A' is a number with the value 65; on the other hand, 
"A" is the character A expressed as a string. Both are represented in memory by the bitstring 
01000001. (Note, however, that "A" is not a valid number and 'A' is not a valid string.) The 
following numeric expressions are all equivalent: 

'B' 

66 

' A' +1 


434 



Resource Description Files 21 


Literals are padded with nulls on the left side so that the literal 'ABC' is stored as shown 
below. 

••ABC" = $00 ABC 

Expressions 

An expression may consist of simply a number or literal. Expressions may also include numeric 
variables, labels, and system functions. 

This table lists the operators in order of precedence with highest precedence first—groupings 
indicate equal precedence. Evaluation is always left to right when the priority is the same. Variables 
are defined following the table. 

Operator Meaning 

1. ( expr ) Parentheses can be used in the normal manner to force 

precedence in expression calculation 

2. -expr Arithmetic (two’s complement) negation of expr 

~expr Bitwise (one’s complement) negation of expr 

! expr Logical negation of expr 

3. exprl * expr2 Multiplication 

exprl / expr2 Division 

exprl % expr2 Remainder from dividing exprl by expr2 

4. exprl + expr2 Addition 

exptrl - expr2 Subtraction 

5. exprl « expr2 Shift left—shift exprl left by expr2bits 
exprl » expr2 Shift right—shift exprl right by expr2 bits 

6. exprl > expr2 Greater than 

exprl >= expr2 Greater than or equal to 

exprl < expr2 Less than 

exprl <= expr2 Less than or equal to 

7. exprl == expr2 Equal 

exprl ! = expr2 Not equal 

8. exprl & expr2 Bitwise AND 


435 




THINK Pascal User Manual 


Operator 

Meaning 

9. 

exprl * expr2 

Bitwise XOR 

10. 

exprl | expr2 

Bitwise OR 

11. 

exprl && expr2 

Logical AND 

12. 

exprl | | expr2 

Logical OR 


The logical operators !, >, >=, <, <=, ==, !=, &&, and I I evaluate to 1 (true) or 0 (false). 

Variables and functions 

Some resource compiler variables contain commonly used values. All SARez variables start with $$ 
followed by an alphanumeric identifier. 

The following variables and functions have string values (typical values are given in parentheses): 
$$Date 

Current date. Useful for putting timestamps into the resource file. The format is generated through 
the ROM call IUDateString. ("Thursday, May 20, 1987") 

$ $ F o rma t ( "formatstring ", arguments) 

Works just like the #printf directive except that $$f ormat returns a string rather than printing 
to standard output. (See the section “Print Directive” earlier in this chapter.) 

$$Name 

Name of resource from the current resource. The current resource is the resource being generated 
in a resource statement, being included from an include statement, being deleted from a 
delete statement, or changed in a change statement. 

For example, to include all 1 DRVR' resources from one file and keep the same information, but 
also set the SYS HEAP attribute: 

INCLUDE "file" 'DRVR' (0:40) AS 
'DRVR' ($ $ID, $$Name, $$Attributes I 64); 

The $$Type, $$ID, $$Name, and $$ Attributes variables are undefined outside of a 
change, delete, include, or resource statement. 

$ $Resource (" filename ", ' type ', ID | " resourceName") 

Reads the resource ' type ' with the ID ID or the name " resourceName" from the resource file 
"filename" , and returns a string. 

$ $ Shell (" stringExpr ") 

Included for MPW-compatibility. In SARez and SADeRez, this returns the null string (" "). In 
MPW’s SARez and SADeRez, it returns the current value of the exported Shell variable [stringExpr). 
Note that the braces are omitted, and the double quotation marks must be present. 


436 



Resource Description Files 


21 


$$Time 

Current time. Useful for time-stamping the resource file. The format is generated through the ROM 
call IUTimeString. ("7:50:54 AM") 

$$Version 

Version number of SARez. C'V3. 0 ") 

These variables and functions have numeric values: 

$$Attributes 

Attributes of resource from the current resource. See the $$Name string variable. 

$$BitField( label, startingPosition, numberOfBits) 

Returns the numberOfBits (maximum of 32) bitstring found startingPosition bits from label. 
$$Byte (label) 

Returns the byte found at label. 

$$Day 

Current day. Range 1-31. 

$$Hour 

Current hour. Range 0-23. 

$$ID 

ID of resource from the current resource. See the $$Name string variable. 

$$Long (label) 

Returns the longword found at label. 

$$Minute 

Current minute. Range 0-59. 

$ $Month 

Current month. Range 1-12. 

$$PackedSize( Start, Row Bytes, RowCount) 

Given an offset (Start) into the current resource and two integers, RowBytes and RowCount , this 
function calls the Toolbox routine UnpackBits () RowCount times. $$PackedSize () returns 
the unpacked size of the data found at start. Use this function only for decompiling resource files. 
An example of this function is found in Piet. r. 

$$ResourceSize 

Current size of resource in bytes. When decompiling, $$ResourceSize is the actual size of the 
resource being decompiled. When compiling, $$ResourceSize returns the number of bytes that 
have been compiled so far for the current resource. (See the ' KCHR ' resource in SysTypes . r for 
an example.) 


437 



THINK Pascal User Manual 


$$Second 

Current second. Range 0-59. 

$$Type 

Type of resource from the current resource. See the $$Name string variable. 

$$Weekday 

Current day of the week. Range 1-7 (that is, Sunday-Saturday). 

$$Word {label) 

Returns the word found at label 

$$Year 

Current year. 

Strings 

There are two basic types of strings: 

Text string " a ..." The string can contain any printable character except 

‘ ” ’ and ‘V. These and other characters can be created 
through escape sequences. (The section “Escape 
Sequences below lists all the escape sequences.) The 
string " " is a valid string of length 0. 

Hex string $ ” bb ..." Spaces and tabs inside a hexadecimal string are ig¬ 

nored. There must be an even number of hexadecimal 
digits. The string $ ” " is a valid hexadecimal string of 
length 0. 

Any two strings (hexadecimal or text) will be concatenated if they are placed next to each other 

with only white space in between. (In this case, returns and comments are considered white 

space.) 

The picture below shows a Pascal string declared as 
pstring [10] ; 

whose data definition is 
"Hello” 


$05 

H 

e 

1 

1 

o 

$00 

$00 

$00 

$00 

$00 


In the input file, string data is surrounded by double quotation marks ("). You can continue a 
string on the next line. A separating token (for example, a comma) or brace signifies the end of the 


438 




Resource Description Files 


21 


string data. A side effect of string continuation is that a sequence of two quotation marks (" ") is 
simply ignored. For example, 

"Hello ""out " 

"there." 

is the same string as 

"Hello out there."; 

To place a quotation mark character within a string, precede the quotation mark with a backslash 
like this 


(\") . 


Escape characters 

The backslash character (\) is provided as an escape character to allow you to insert nonprintable 
characters in a string. For example, to include a newline character in a string, use the escape 
sequence \n. 

These are the valid escape sequences: 


Escape 



Printable 

sequence 

Name 

Hex value 

equivalent 

\t 

Tab 

$09 

None 

\b 

Backspace 

$08 

None 

\ r 

Return 

$0A 

None 

\n 

Newline 

$0D 

None 

\f 

Form feed 

$0C 

None 

\ v 

Vertical tab 

$0B 

None 

\? 

Rubout 

$7F 

None 

w 

Backslash 

$5C 

\ 

V 

Single quotation mark 

$3A 

1 

\" 

Double quotation mark 

$22 

«« 


You can also use octal, hexadecimal, decimal, and binary escape sequences to specify characters 
that do not have predefined escape equivalents. The forms are: 


Base 

Number form 

Digits 

Example 

2 

\0B bbbbbbbb 

8 

\0B01000001 

8 

\ooo 

3 

\101 

10 

\0D ddd 

3 

\0D065 

16 

\0 xbb 

2 

\0X41 

16 

\ $ hh 

2 

\ $41 


439 



THINK Pascal User Manual 


Here are some examples: 


\077 

/* 

3 octal digits */ 


\ OxFF 

/* 

'Ox' plus 2 hex digits 

*/ 

\$F1\$F2\$F3 

/* 

'$' plus 2 hex digits 

*/ 

\0d099 

/* 

'0d' plus 3 decimal digits */ 


Note to C programmers: An octal escape code consists of exactly three digits. 

For instance, to place an octal escape code with a value of 7 in the middle of an 
alphabetic string, write AB\007CD, not AB\7CD. 

You can select the Don’t Escape Characters option in SADeRez to print characters that would 
otherwise be escaped (characters preceded by a backslash, for example). Normally, only characters 
with values between $20 and $D8 are printed as Macintosh characters. With this option, however, 
all characters (except null, newline, tab, backspace, form-feed, vertical tab, and rubout) will be 
printed as characters, not as escape sequences. See Chapter 23 “SADeRez” for details. 


440 



Using SARez 

22 


Introduction 

This chapter describes SARez, a utility that creates resources from a textual description. 

SARez started out life as Rez, a tool in Apple’s Macintosh Programmer’s Workshop (MPW). MPW 
has a command-line interface, much like UNIX. At times it will seem SARez works a bit oddly or 
has options you can’t use. This is because of its heritage. But, despite its odd upbringing, SARez is 
still a powerful and useful tool. 

Topics covered In this chapter 

• What is SARez? 

• Choosing input files 

• Choosing an output file 

• Setting options 

• Saving and restoring options 

• The message window 

What Is SARez? 

SARez (which means Stand-Alone Rez and is pronounced “SayRez”) creates the resource fork of a 
file from a textual description. That textual description is found in one or more resource 
description Hies. The format for resource description files is described in Chapter 21. 

If you followed the directions in Chapter 2, “Installing THINK Pascal,” SARez is in the folder Rez 
Utilities inside THINK Pascal 4.0 Utilities. 


441 



THINK Pascal User Manual 


Running SARez 

When you run SARez, you see the dialog below. To compile a resource description file, you open a 
SARez options file you previously saved, or you can manually set the input files, output files, and 
other options. When you click the button titled “Sarez,” SARez compiles your files. If there are no 
errors, it exits. If there are errors, it displays them in the message window, described below. You 
can then edit, print, or save the contents of the messages window. To cancel without compiling, 
click the button titled “Cancel,” or choose Quit from the File menu. More information on setting 
and saving your options is below. 


Untitled 


r Sarez Options 


Resource Output File 

Z=1 


Rez.out 


Type 

Creator 


???? 


(8) Rewrite resource Tile 

□ Make resource file read-only 
r Resource Rlignment 
I (i) Byte OUiord O LonglUord 

O Merge resources into resource file 

□ OK 1o replace protected retoures 


□ Progress information 

□ Redeclared types ok 

□ Modification date 

[ Description Files... ] 
[ ^Include Paths... ) 
[ Include Paths... ) 
[ Preprocessor... ] 
[ Redirection... ] 


i-Command Line 

SARez 


r Help- 

Rez is a tool used to compile resources. 


[ Cancel 

I Sarez 
3T“ 


) 


The SARez dialog has two parts. In the first part, enclosed in a box titled “Sarez Options,” you 
choose your files and options for SARez’s operation. In the second part, containing the boxes 
named “Command Line” and “Help,” you can see how the options work. 

The Command Line box may seem out of place in a Macintosh program. But, remember SARez 
started life as Rez, an MPW tool. The Command Line box displays a Rez command line that has the 
same options set as the SARez dialog. You cannot edit this line. 

The Help box gives you information about the dialog. When you click on an option or a box, a 
description of it appears in this box. 


442 














Using SARez 22 


Choosing Input Files 

To choose the description files to use as input, click on the Description Files... button to display a 
dialog. The one shown below has Types. r (in the RIncludes folder) and Sample. r chosen as 
the description files. 


|<3 Rez/DeRez | 




□ My Types 

<> 

ez) Moose 


CD RIncludes 




□ Sample.r 


i ] 




[ Driue ] 




[ Done ] 



5 

[ Cancel ] 

(S) Only files ending in .r O RH 

text files 

Resource Description Files: 




:Rlncludes:Types.r 

o 



Sample.r 

r 

K «<><• ii 




f 1 



o 


■ 

— 



These radio buttons determine which files appear in the top list: 

Button Description 

Only Files Ending in . r Displays files with names ending in . r, Such as Sample. r 
All Text Files Displays all text files, regardless of their names 

You can add and remove files with these commands: 

• To add a description file, select it from the standard file list in the top pane, and dick 
Open. Its name is added to the list in the lower pane. You can also double-click on the 
file to add it to the bottom list. 

• To remove a description file from the bottom list, select it, and click Remove. 

• When you’ve selected all your description files, click Done. 

• To cancel what you’ve done and leave the list of files as it was, click Cancel. 

Note: If you don’t select any files in the Description Files... dialog, SARez will use 
the alternate input file set in the Redirection... dialog. If you don’t select an alter¬ 
nate file in the Redirection... dialog, SARez will act as if it were reading an empty 
file. Most of the time, you’ll want to use the Description Files... dialog. 


443 





THINK Pascal User Manual 


Choosing an Output File 

To choose the file SARez writes your resources to, use the Resource Output File box, shown below. 
This box is part of the SARez dialog. 

r Resource Output File 

Type 
Creator 

-® Rewrite resource file 

□ Make resource file read-only 

- Resource Alignment. 

j <§> Ryte O Word O LongWord 

-O Merge resources into resource file 

□ OK to ropiote protected resoures 


Rez.out 


RPPL 

???? 
a a a a 


To choose the file, click o n the button in the upper left hand corner of the box. This pop-up menu 
appears. 

v Write output to ffez. out 
Select an enisting output file... 

Write output to a new file... 


This is what the choices mean: 


Option Description 

Write output to Writes to file called Rez . out, creating it if necessary. This is the 
Rez.out default 


Select an existing Displays a standard file dialog that lets you choose an existing file, 
output file... In the dialog, you can choose what it displays: only MPW tools and 

applications or all files. 


Write output to a Displays a standard file dialog that lets you enter the name of a new 
new file... file to create. 


In the Type and Creator boxes, you enter the type and creator of the file. These must be four-letter 
values. If you are writing to an existing file, SARez changes the type and creator of the file to the 
new values. 


444 













Using SARez 22 


The rest of the buttons control how SARez treats the resource fork i t creates. These two determine 
whether to overwrite the existing resource fork: 


Option 

Rewrite Resource 
File 


Description 

Erases the file’s resource fork and replaces it with the resources cre¬ 
ated from your description files. This is the appropriate choice for 
creating a new file or overwriting an old one. 


Merge Resources Keeps the resource fork and appends your resources to them. If 
into Resource File one of your resources have the same type and ID as an existing re¬ 
source and the existing resource isn’t protected, your resource will 
overwrite it. 


If you choose Rewrite Resource File, you’ll see two more options: 

Option Description 

Make Resource File Read-only Sets the mapReadOnly flag in the resource map. 

Resource Alignment Lets you choose how you want your resources 

aligned: along byte, word, or longword 
boundaries. The default is byte 

If you choose Merge Resources into Resource File, you’ll see this option: 

Option Description 

OK to Replace Overrides the protected bit in resources. Even if an existing re- 

Protected Resources source has the protected bit set, SARez will overwrite it when a new 
resource has the same type and ID. 


445 




THINK Pascal User Manual 


Setting Options 

The SARez Options box contains several check boxes for setting some options, several buttons that 
display dialogs for more detailed information, and the Resource Output File box for setting the 
output file. This section describes all the buttons and check boxes in the right column, except for 

Description Files.which you’ve already seen in the section “Choosing Input Files.” And the 

Resource Output File box is described in the section “Choosing Output Files” above. 


r Sarez Options 


Resource Output File 
iRez.out I 


Type 

Creator 


RPPL 


???? 


(•) Reuirite resource file 

□ Make resource file read-only 

Resource Alignment. 

©Byte O Word O LonglDord 


., □ Progress information 
! □ Redeclared types ok 
| □ Modification date 

| [ Description Files.T") 


O Merge resources into resource file 

□ OK to i'<*p!a<e protected ixnoures 


C 


^Include Paths... 


L 


Include Paths... 


Preprocessor... ] 


Redirection... 


The three check boxes in the upper-right hand corner control these options: 


Choice 

Progress 

information 


Description 

If selected, SARez writes information on each type and resource 
created and the SARez version number to the error file (selected in 
the Redirection... dialog). 


Redeclared types If selected, SARez will not print warning messages to the error file 
OK when a resource type is redeclared. 


Modification date If selected, SARez doesn’t change the output file’s modification 
date. Be careful. If an error occurs, SARez sets the output file’s 
modification date to zero, even if you select this option. 


446 












Using SARez 22 


Setting the search paths for #include and include 

The #Include Paths... and Include Paths... dialogs let you specify folders (also called directories or 
search paths) that SARez will search when it looks for an include or #include file. The #Include 
Paths... dialog below has the folder Rlncludes in the list of folders to be searched.The Include 
Paths... dialog is similar. 


(Rdd Current Directory: ] 
€3 Rez/DeRez] 


CD My Types 

<> 

CD Rlncludes 


^Include Search Paths: 

:Rlncludes: 



<> 


cz) Moose 

i »•)«<( 1 

[ Driue ] 


[ Done ] 
[ Cancel ] 


[ Open ] 

It » <l{l Jl 

[ »«rnm*e ] 


You can add and remove folders with these commands: 

• To add a folder to the list of folders searched, select it from the standard file list in the 
top pane, and click Add. It’s name is added to the list below. 

• To add the folder you’re currently in, click Add Current Directory. For example, clicking 
Add Current Directory in Figure 10-6 would add Rez/DeRez to the list. 

• To open a folder to see the other folders in it, select it, and click Open. You can also 
double click on it. 

• To remove a description file from the bottom, select it, and click Remove. 

• When you’ve selected all the folders you want, click Done. 

• To cancel what you’ve done and leave the list of folders as it was, click Cancel. 






THINK Pascal User Manual 


Defining and undeflnlng macros 

The Preprocessor... dialog lets you define and undefine macro variables. In the Defines box, enter 
the variables you want defined and their values. Use a new line for each pair of variables and val¬ 
ues. If you don’t enter a value, the variable is set to the null string (" "). In the Undefines box, enter 
the variables you want undefined. For example, setting up the Preprocessor... dialog below is like 
adding these lines to the beginning of each description file: 

#define LIGHTSPEED 186282 
#define THINK_PASCAL 
#undef DESK ACC 


[-Preprocessor...- 

Defines: Undefines: 


LIGHTSPEED 186282 
THINK—PHSCHL 

<> 


DESK-RCCj 

<> 


Q 



2 




SARez -d •LIGHTSPEED 186282* -d THINK_PASCAL -u DESK-ACC 


llnln 


Preprocessor variables can be DEFINE'd and UNDEFINED in this dialog. 

[ Cancel J 

K Continue ]| 


448 





Using SARez 22 


Choosing an error and alternate input files 

The Redirection... dialog lets you choose an alternate input file and the error file. The alternate in¬ 
put file is what SARez reads if there are no description files set in the Description Files... dialog. 
The error file is an additional place to write out error, warning, and status messages. SARez always 
writes its messages to the messages window, described below. The dialog below sets the error file 
to be Errors (on a disk named Moose) and sets no alternate input file. 


-Redirection...- 

Input _ Error (g) * Q n 

| | |Moose:Errors [ 




SARez 1 Akbar:Errors 



[ Cancel ] 
|[ Continue 1 

Rez can read standard input and send warnings to diagnostic output. 


Clicking on the button under Input brings up the pop-up menu below. 

Input _ 

SNo input 
Existing File... 
Standard Input 
Null Deuice 


This is what the options mean: 


Choice Description 

No Input The same as setting the alternate input file to be an empty file. 


Existing File... 


Lets you select a file to read from. 


Standard Input These act the same as No Input. 
Null Device 


Note: SARez uses the input file you set here only if you don’t choose description 
files in the Description Files... dialog. Most of the time, you’ll want to use the 
Description Files... dialog and leave the alternate input file set to No Input. 


449 




THINK Pascal User Manual 


The Error menu lets you choose an additional place to write error, warning, and status messages. 
SARez always writes its messages to the messages window, described below. You might use this 
menu if you always want your messages saved to a particular file. 

Clicking on the button under Error brings up the pop-up-menu below. 

Error _ 

VNo Output 
Neui File... 

EHisting File... 

Standard Output 
Standard Diagnostic 
Null Device 


This is what the options mean: 


Choice 
No Output 


Description 

Writes messages only to the messages window. 


New File... 


Lets you create a file to write messages to. 


Existing File... 


Lets you choose an existing file to write messages to. 


Standard Output These act the same as No Output 

Standard Diagnostic 
Null Device 


If you select an existing file as your error file, you’ll see two radio buttons above the Error menu, 
shown below. 


Error ® > Q >> 

Moose:Errors ~| 

You can choose whether or not to overwrite the existing file: 

Choice Description 

^ The new messages will overwrite the existing file. 

^ The new messages will be appended to the end of the existing file. 


450 


Saving and Restoring Options 

SARez lets you save your option settings in a SARez options file. This options file contains the 
names of your input and output files, in addition to all the other option settings. When the SARez 




Using SARez 22 


dialog box is the front window, the File menu contains these commands to let you save and restore 
your settings: 


Command 

New 

Open... 

Save 


Save As... 


Description 

Clears your current settings and lets you create a new options file. 

Lets you choose a file you previously saved and restores those settings. 
Saves the current settings to the options file you’re using. If you aren’t using 
an options file (that is, you haven’t opened or saved one), it lets you create 
one. 

Lets you create an options file containing your current settings. 


When you can double-click on a SARez options file in the Finder, SARez doesn’t display its dialog. 
It just compiles your files, displays your errors (if any), and exits. 


The Messages Window 

If SARez encounters no problems while compiling your files, it will just exit to the Finder when it’s 
done. But if SARez needs to display any its error, warning, or status messages, it uses the messages 
window, shown below. 


File ”Samp 1e.r“; Line 1; »»» SfiRez - Can't find the dec 1aration 
for the resource type 'pict' <0x70696374). 

File "Sample.r"; »»» SfiRez - Since errors occured, fiez.out's 
resource fork was not written. 

Hi 

<> 

o 

oi wiiWinMiMisiwMniiwao 

a 


You can freely edit the contents of the message window, as if it were a text editor. You can add 
your own comments and cut, copy, or paste, using the Edit menu. 


451 














































































































THINK Pascal User Manual 


When the messages window is in the front, the File menu contains these commands to let you save 
and print your messages: 


Command 

Close 

Save 

Save As... 
Page Setup... 
Print... 


Description 

Closes the messages window. 

Saves your messages to a file. If you haven’t chosen a file yet, it lets 
you choose one. 

Lets you choose a file to save your messages to. 

Displays the standard Page Setup... dialog for your printer. 

Lets you print the contents of the messages window. 


With the Font and Size menus, you can change the font SARez displays and prints your messages 
with. 


Note: If you always save your messages to a particular file, you can use the 
Redirection... dialog to choose an error file. SARez will write your messages to 
both the messages window and the error file. 


452 



Using SADeRez 

23 


Introduction 

This chapter describes SADeRez, which creates a text representation of the resource fork of a file. 

SADeRez started out life as DeRez, a tool in Apple’s Macintosh Programmer’s Workshop (MP W). 
MPW has a command-line interface, much like UNIX. At times it will seem SADeRez works a bit 
oddly or has options you can’t use. This is because of its heritage. But, despite its odd upbringing, 
SADeRez is still a powerful and useful tool. 

Topics covered in this chapter 

• What is SADeRez? 

• Choosing input files 

• Choosing output files 

• Setting options 

What Is SADeRez? 

SADeRez (which stands for Stand-Alone DeRez and is pronounced “Say Dee’ Rez”) creates a text 
representation (a resource description file) of the resource fork of a file, according to the resource 
type declarations in one or more resource description files. 

If you followed the directions in Chapter 2, “Installing THINK Pascal,” SADeRez is in the folder Rez 
Utilities inside THINK Pascal 4.0 Utilities. 

A resource description file is a file of type declarations in the format used by the resource com¬ 
piler, Rez. The type declarations for standard Macintosh resources are in the files Types . r and 
SysTypes . r, in the {RIncludes} folder. If no resource description file is specified, the output 
consists of data statements giving the resource data in hexadecimal form, without any additional 
format information. The format for resource description files is described in Chapter 21. 

Note: SADeRez uses resource description files as both input and output The input 
description files define resource types (such as 'WIND'), and the output descrip¬ 
tion file defines actual resources (such as the document window for your 
application) 

If the output of SADeRez is used as input to SARez, with the same resource description files, it pro¬ 
duces the same resource fork that was originally input to SADeRez. SADeRez is not guaranteed to 
be able to run a declaration backwards; if it can’t, it produces a data statement instead of the 
appropriate resource statement. 



THINK Pascal User Manual 


\SADeRez ignores all include (but not #include), read, data, change, delete, and 
resource statements found in the resource description files. (But it still parses these statements 
for correct syntax.) 

Running SADeRez 

When you run SADeRez, its dialog is greyed out, except for the File To Decompile button. You can 
either open a SADeRez options file you previously saved or choose a file to decompile. Now, the 
dialog looks like the one below. To continue, you can change your options and click the button 
titled “Saderez.” If there are no errors, SADeRez compiles your file and exits, If there are errors, 
SADeRez displays them in the messages window, described below. To cancel without decompiling, 
click the button titled “Cancel” or choose Quit from the File menu. More information on choosing 
and saving your options follows. 


Untitled 


-Sadere z Options 

( File to decompile ] 


Types Files... ] 


^INCLUDE Paths... 


UJidth of decompiled strings |40 | 

□ No warnings for redeclared types j 

□ Progress information 

□ Write Rez 1.0 compatible output 
f~l Don't escape characters 


Output 


Error 


jTypes. 

I Decompile Skip 



2 

2 


£ 

2. 

.-Preprocessor 


Define 


Undefine 



it 




2 


sB 


r-Command Line- 

SADerez Moose :file 


[ Cancel J 

DeRez — the resource decompiler. This tool can decompile a resource file 
into a text representation suitable for Rez input. 

K Saderez j] 


The SADeRez dialog has two major parts. In the first part, enclosed in a box titled “Saderez 
Options,” you set options for SADeRez’s operation. There is more information about these options 
below. In the second part, containing the boxes named “Command Line” and “Help,” you can see 
how the options work. 

The Command Line box may seem out of place in a Macintosh program. But, remember SADeRez 
started life as DeRez, an MPW tool. The Command Line box displays a DeRez command line that 
has the same options set as the SADeRez dialog. You cannot edit this line. 

The Help box gives you information about the dialog. When you click on an option or a box, a 
description of it appears in this box. 


454 













Using SADeRez 23 


Choosing Input Files 

You must choose at least two input files. First, choose a resource file, a file containing resources 
you want decompiled. Next, choose one or more resource description files, containing definitions 
of resource types. You specify these with the buttons in the upper-left-hand corner of the SADeRez 
dialog, as shown below. 


[ File to decompile ) 

[ Types Files... ) [^INCLUDE Paths...) 

Choosing the resource file 

First, you’ll need to choose a resource file. The File To Decompile button displays a standard file 
dialog that lets you select one. The dialog offers to let you select any file or only an application or 
MPW tool. 

Choosing a description file 

The Types Files... button displays a dialog that lets you select one or more description files. The 
dialog below has Types . r (in the RIncludes folder) selected as the description file. 


RIncludes | 




□ Cmdo.r 

5 

a Moose 


D MPUITypes.r 




D Pict.r 


f 1 


□ SysTypes.r 


[ Driue 1 


D Types.r 


_ _ _ * 




[ Done ] 



<> 

[ Cancel ] 

1 (•) Files ending in .r OBHtent 

files 

Resource Description Files: 




:Rlncludes:Types.r 

o 




i «<><> J 




[ Rernoue ] 



o 


n 

— 



455 








THINK Pascal User Manual 


These buttons choose which files appear in the top list: 

Option Description 

Only Files Ending in .r Display only files that end in . r, such as Types . r 

All Text Files Display all text files, regardless of their names 

You can add and remove files with these commands: 

• To add a description file to the list in the bottom pane, select it in the standard file list in 
the top pane, and click Open. It’s name is added to the list below. You can also double¬ 
click on the file to add it to the bottom list. 

• To remove a description file from the bottom list, select it, and click Remove. 

• When you’ve selected all your description files, click Done. 

• To cancel what you’ve done and leave the list of files as it was, click Cancel. 

Choosing #include paths 

If any of your description files contain #include statements, you’ll need to select the folders (also 
called directories or search paths) in which SADeRez can find them. To choose these, click on the 
#INCLUDE Paths... button to display a dialog. The dialog below has the folder RIncludes in the 
list of folders to be searched. 



Note: SADeRez ignores include statements in the resource description files. 


456 






Using SADeRez 23 


You can add and remove folders with these commands: 

• To add a folder to the list of folders searched in the bottom pane, select it in the stan¬ 
dard file list in the bottom pane, and click Add. It’s name is added to the list in the 
bottom pane. 

• To add the folder you’re currently in, click Add Current Directory. In the dialog above, 
clicking Add Current Directory would add Rez/DeRez to the bottom list. 

• To open a folder to see the other folders in it, select it, and click Open. You can also 
double click on it. 

• To remove a description file from the bottom list, select it, and click Remove. 

• When you’ve selected all the folders you want, click Done. 

• To cancel what you’ve done and leave the list of folders as it was, click Cancel. 

Choosing Output Files 

You need to choose an output description file. This will contain the definitions of the resources in 
your resource file. You can also choose an error file, an additional place to write error, warning, 
and status messages. SADeRez always writes its messages to the messages window, described 
below. You would choose an error file if you always want your messages saved to a particular file. 

You choose these files with the buttons in the lower-left-hand corner of the SADeRez Options box. 
The buttons in Figure 11-5 set the description file to be the new file Test. r and the error file to be 
the existing file Errors (both on the disk Moose). 


I Output _ Error (§) > O >> I 

i|Moose:Test.r 


Moose:Errors | 


Clicking on the button under either Output or Error brings up this pop-up menu. 

■SMo Output 
New File... 

Existing File... 

Standard Output 
Standard Diagnostic 
Null Deuice 


457 





THINK Pascal User Manual 


This is what the options mean: 

Option Description 

No Output Doesn’t write out the output. 

New File. .. Le ts you create a file t o write to. 

Existing File... Lets you select an existing file to write to. 

Standard Output These act the same as No Output 

Standard Diagnostic 
Null Device 


If you select an existing file as an output file, you’ll see these two radio buttons above the menu. 
(In the Output menu, the buttons are labeled “>” and “»”). 


Error ® > Q >> 
lMoose:Errors 1 


These let you choose whether or not to overwrite the existing file: 


Option Description 

> or > The new output will overwrite the existing file. 

>> or » The new output will be appended to the end of the existing file. 


Setting Options 

The rest of the SADeRez Options box lets you select options describing how to decompile your file. 
The list of options, shown below, is between the input and output buttons. 

Width of decompiled strings 140 ] 

| □ No warnings for redeclared types { 

! □ Progress information 
| □ Write Rez 1.0 compatible output 
I □ Don't escape characters 


458 





This is what the options mean: 


Using SADeRez 23 


Option Description 

Width of Sets the maximum string size. It must be in the range 2-120. This 

decompiled strings controls string width in the output 

No warnings for If selected, SADeRez will not print a warning message to the error 

redeclared types file when a resource type is redeclared in the description files. 

Progress If selected, SADeRez writes its version number and information on 

information the decompiled resources to the error file. 

Write Rez 1.0 If selected, SADeRez will generate a description file that is 

compatible output backward compatible with Rez 1.0. 

Don’t escape If selected, characters that are normally escaped (such as \ Oxf f) 

characters are no longer escaped. Instead they are printed as extended 

Macintosh characters. (Note: Not all fonts have all the characters 
defined.) Normally, only characters with values between $20 and 
$D8 are printed as Macintosh characters. With this option, however, 
all characters (except null, newline, tab, backspace, form feed, ver¬ 
tical tab, and rubout) are printed as characters, not as escape 
sequences. 

Choosing the types to decompile 

In the Types box, you can choose which types of resources SADeRez decompiles. This box 
contains two lists: 

Option Description 

Decompile If you want to decompile only a few resource types, enter their names here. 

For example, with the box below, SADeRez will decompile resources of 
type 'WIND' only. 


-Types—. 

Decompile Skip 



459 










THINK Pascal User Manual 


Option 

Skip 


Description 

If you want to decompile every resource type with a few exceptions, enter 
the exceptions here. For example, with the box below, SADeRez will 
decompile all resources, except those of type ' PICT'. 


-Types- 

Decompile Skip 

i i 

I ! 

PICT 

a 


You can use only one list at a time. Whenever one has anything in it, the other is greyed out. If you 
don’t use either list, SADeRez will decompile everything in the input file. 


Preprocessor 

In the Preprocessor box, you can define and undefine macro variables. In the Defines list, enter the 
variables you want defined and their values. Use a new line for each pair of variables and values. If 
you don’t enter a value, the variable is set to the null string (" "). In the Undefines list, enter the 
variables you want undefined. For example, setting up the Preprocessor box as shown below is 
like adding these lines to the beginning of each resource description file: 


#define c 186282 
#define PASCAL 
#undef DESK ACC 


—Preprocessor 

Define 

Undefine 


c186282 

a 


DESK-DCC 

3 

PRSCRL 

1 

a 



■ 

3 


Saving and Restoring Options 

SADeRez lets you save your option settings in a SADeRez options file. This options file contains the 
names of your input and output files, in addition to all the other option settings. 


460 
















Using SADeRez 23 


When the SADeRez dialog box is in the front, the File menu contains these commands to let you 
save and restore your settings: 


Command 

New 

Open... 

Save 


Save As... 


Description 

Clears your current settings and lets you create a new options file. 

Lets you choose a file you previously saved and restores those settings. 
Saves the current settings to the options file you’re using. If you aren’t using 
an options file (that is, you haven’t opened or saved one), it lets you create 
one. 

Lets you create an options file containing your current settings. 


When you can double-click on a SADeRez options file in the Finder, SADeRez doesn’t display its 
dialog. It just compiles your files, displays your errors (if any), and exits. 


The Messages Window 

If SADeRez encounters no problems while decompiling your file, it will just exit to the Finder when 
it’s done. But if SARez needs to display any its error, warning, or status messages, it uses the 
messages window, like this one: 


File "myResources.r**j Line 1; *** SRDeRez - OS error -43 (Error 
message file not available) during open of "foo". 

File "myResources.r"; Line 1; »** SRDeRez - Fatal Error, can't 
recover. 

m 

<> 

<> 

01 Hi 1 iiiiliii i ••• •• • ••lo 

2 


You can freely edit the contents of the message window, as if it were a text editor. You can add 
your own comments and cut, copy, or paste, using the Edit menu. 


461 



































































































































THINK Pascal User Manual 


When the messages window is in the front, the File menu contains these commands to let you save 
and print your messages: 


Command 

Close 

Save 


Save As... 
Page Setup... 
Print... 


Description 

Closes the messages window. 

Saves your messages to a file. If you haven’t chosen a file yet, it lets 
you choose one. 

Lets you choose a file to save your messages to. 

Displays the standard Page Setup... dialog for your printer. 

Lets you print the contents of the messages window. 


With the Font and Size menus, you can change the font SADeRez displays and prints your 
messages with. 


Note: If you always save your messages to a particular file, you can use the 
Redirection... dialog to choose an error file. SADeRez will write your messages to 
both the messages window and the error file. 


462 



Using SAPostRez 

24 


Introduction 

This chapter describes SAPostRez, which converts a resource file for use with a MacApp program. 

Topics covered In this chapter 

• What is SAPostRez? 

• Using SAPostRez 

What is SAPostRez? 

SAPostRez (which stands for Stand-Alone PostRez and is pronounced “Say Post Rez”) converts 
each 'cmnu' resource in a file into a ' MENU' resource and creates an 'mntb' resource. Your 
MacApp program uses the mntb resource to translate menu choices to command numbers. For 
more information on cmnu and mntb resources, see your MacApp documentation. 

If you followed the directions in Chapter 2, “Installing THINK Pascal,” SAPostRez in the folder Rez 
Utilities inside THINK Pascal 4.0 Utilities. 

Using SAPostRez 

To start SAPostRez, double-click on its icon. You see this dialog : 


C3 Rez/DeRez | 


D sample.rsrc 

CD {Rlncludes} 

£ 

(=5 Moose 

l J 



[ Driue ] 

j{ Concert J 



( Quit ] 


M Show “.Rsrc” files only 98R 
£3 Leaue behind “CMNU” resources 96L 


463 





THINK Pascal User Manual 


This is what the options mean: 

Option Description 

Show “.Rsrc” files only If selected, only files ending in .rsrc, like sample.rsrc, 

appear in the file list. 

Leave behind “CMNU” resources If selected, SAPostRez doesn’t remove the 'cmnu' 

resources from the resource file after it converts them. 

This is useful if you’re still developing your program 
and may change your program’s menus or command 
numbers. 

To convert the ' cmnu' resources in a file, select the file and click on the Convert button. 

SAPostRez converts the ' cmnu' resources and displays its dialog again. SAPostRez does not create 

a new file but adds or changes resources in the file you select. 

To quit from SAPostRez, click on the Quit button. 



THINK Pascal' 

PART SIX 

Appendices 

A What’s New 
B ANS Pascal Compatibility 
C Porting to THINK Pascal 
D Error Messages 





What’s New 

A 


Introduction 

This chapter describes many of the new features in THINK Pascal 4.0. 

Topics covered In this appendix 

• Compatibility with earlier releases 

• System 7.0 compatibility 

• Working with large projects 

• Working with small projects 

• New and improved commands 

• Enhanced THINK Class Library 

• Other changes 

Compatibility with Earlier Releases 

THINK Pascal 4.0 is completely compatible with THINK Pascal 2.0 and later versions. The new 
version automatically converts project documents created with the older versions, discarding all the 
object code. THINK Pascal 4.0 can read THINK Pascal 2.0 and 3 0 libraries and source files (even 
those saved as Entire Document) without modification. 

System 7.0 Compatibility 

THINK Pascal 4.0 works under System 7.0. It lets your applications take full advantage of the new 
system software. THINK Pascal 4.0 does the following: 

• Runs with 32-bit addressing 

• Produces applications that run with 32-bit addressing Oike all versions since THINK 
Pascal 2.0) 

• Runs with virtual memory 

• Handles the required AppleEvents 

• Recognizes all Toolbox routines in Inside Macintosh VI 

• Contains the THINK Class Library 1.1, with System 7.0 support. 

THINK Pascal lets you work with the alias of a project file. The project tree begins where the 
original project is. However, THINK Pascal does not support aliases in these cases: 

• Putting aliases in a project 

• Using an alias as a project’s resource file 

• Inserting an alias of a folder in your THINK Pascal tree or project tree. 


467 



THINK Pascal User Manual 


Working with Large Projects 

THINK Pascal 4.0 makes it easier to work with large projects. It supports applications with larger 
jump tables, multi-segment code resources, and some extensions to the uses clause. 

Far CODE 

In previous versions of THINK Pascal, large programs could run out of space for the jump table. In 
THINK Pascal 4.0, you have an almost unlimited amount of space for the jump table with the “Far 
CODE” option in the Set Project Type... dialog. For more information, see “Building applications 
with large jump tables” in Chapter 12, “Building Projects.” 

Multi-segment code resources 

THINK Pascal 4.0 lets you create multi-segment code resources, such as cdevs, INITs, XCMDs, and 
XFCNs. THINK Pascal already supports multi-segment applications, device drivers, and desk 
accessories. Now, any kind of THINK Pascal project can have multiple segments. For more 
information, see “Multi-segment code resources” in Chapter 12, “Building Projects.” 

Extensions to the USES clause 

Specifying the dependencies between the Files in large projects is easier with some extensions to 
the uses clause. If you turn on the “USES Extensions” option in the Compiler Options... dialog, 
THINK Pascal lets you use these features: 

• Propagated uses. If your unit uses other units, any unit that uses your unit also uses 
those units automatically. 

• Implementation uses. You can put a uses clause in a unit’s implementation section. 

For more information, see “The uses clause,” in Chapter 10, “Units and Libraries.” 

Working with Small Projects 

THINK Pascal 4.0 helps out programmers who write smaller projects. It can automatically create a 
skeleton for small projects, print and save the Text and Drawing Windows, and includes an 
improved AppleEdit DA. 

Instant project 

If you’re writing a small project, with only one or two source files, the Instant Project option in the 
New Project... dialog gets you started programing quicker. This option creates all this for you 
automatically: an empty source File, a project file that contains the source File, and a folder to hold 
the project File and source file. 


468 




What's New 


A 


For example, if you name your program Homework, THINK Pascal creates the project file 
Homework. n and source file Homework. p: 


Homework.if i 

upiions rlie ouna oraerj 

Runtime .lib 

aize 

0 

Interface.lib 

0 

03® V R Homework .p 

0 

rofj/Codi* Sir* 

0 


_ \< 


Homework.p 


program Homework; 

{ Insert your declarations here } 

begin 

{ Insert your program oode here } 


k>l 


kM'T ' . ' '. V .10 


And it creates the folder Homework /: 


Deuelopment 

l 

3 items 21 ,800 k in disk 28,165k 

If )saEB555^g Homework f I-- — =bUI 

□ JL. 

2 items 21,800K in disk 28,165K available 


<> 

ObjectDraw f 

mZJ-o 1 py 


Homework.p Homeworks 



<?l .. 15 

«3] 


For more information, see “Creating small projects” in Chapter 7, “Working with Projects.” 

The Text and Drawing Windows 

If your programs use the Text or Drawing windows, you’ll appreciate THINK Pascal’s enhanced 
support. You can now do the following: 

• Print the windows with the Print... command. 

• Save the contents of the windows with the Save As... command. THINK Pascal saves 
the contents of the Text Window as a Teach Text file and the contents of the Drawing 
Window as an ObjectDraw file. (ObjectDraw is the drawing program you create in 
Chapter 4, “Tutorial: ObjectDraw.”) 

New AppleEdit DA 

The AppleEdit DA (tf Edit) that comes with THINK Pascal in the THINK Pascal 4.0 
Utilities folder has these new features: 

• It’s 32-bit clean, so you can run it under System 7.0 in 32-bit addressing mode. 

• It lets you print your files. 


469 






































































THINK Pascal User Manual 


New and Improved Commands 

THINK Pascal 4.0 makes it easier to select menu commands with these enhancements: 

• In previous versions of THINK Pascal, many commands performed different actions 
when you held down the Shift key. In THINK Pascal 4.0, these commands now have 
different names when you hold down the Shift key. There’s more information on these 
commands later in this section. 

• After you select a menu, you can hold down a modifier key to see additional choices. 
Previously, you had to hold down the modifier key before you selected the menu. For 
example, select the Debug menu. Then hold down the Option key. You see Pull Stops 
become Pull All Stops. Release the Option key and hold down the Shift key. You see 
LightsBug become New LightsBug and Monitor become Use Monitor. 

• You can use the Option and Shift keys in command-key combinations. For example, to 
choose Save, press Command-S; to choose Save All, press Command-Option-S. 

• The Command-key equivalent for the Print... command is now Command-P. The 
command-key for bringing the project window to the front is changed to Command-0 
(Command-Zero). 

Dialog command keys 

Many dialogs in THINK Pascal let you choose options and click buttons with command keys. In 
previous versions, you didn’t always know what those keys were. THINK Pascal 4.0 lets you see 
them. After you hold down the Command key for a short time, THINK Pascal shows the command- 
key equivalents next to the options and buttons. For example, this is what the Find... dialog looks 
like after you hold down the Command key: 


Search for 



[[ Find %F )| 
[Don’t Find %D ) 

[ Cancel 96. ) 


E Whole Words 9§UJ □ Multi-File Search... 9f>R 
□ Match Case 8§M 


Shift key menu options 

In previous versions of THINK Pascal, many commands performed different actions when you held 
down the Shift key. In THINK Pascal 4.0, these commands now have different names when you 
hold down the Shift key. When you hold down the Shift key, Monitor (in the Debug menu) 


470 





What’s New 


becomes Use Monitor, LightsBug (in the Debug menu) becomes New LightsBug, and Check 
Syntax (in the Run menu) becomes Compile. Here is what these commands do: 

• The Use Monitor command lets you choose which debugger you use when THINK 
Pascal comes to an exception. 

• The New LightsBug command creates a new LightsBug window. 

• The Compile command compiles the current edit window and updates the project 
document. 

Adding multiple files to your project 

The Add Files... dialog lets you add several files to your project at once. To see Add Files..., hold 
down the Option key as you select the Project menu. For more information, see “Adding Files to 
Projects” in Chapter 7, “Working with Projects.” 


|C5) Interfaces | 


III I II III 11 i 1 

i <— iflkbar 

□ Picker.p 1 


□ PictUtil.p I 

( ^ i 

D Power.p I 

[ Driue ] 

D PPCTooIBoh.p P 


D PrintTraps.p I 

\ Done 1 

D Processes.p 1 

t___ > 

D Profile.p |C 

y l Cancel ] 


PrintCalls.Lib 

<> 

If QHH h 

Printing.p 


Wf HCla Jl 

Script.p 


[ Rdd Rll ] 

Objlntf.p 




<> 

[ Rornow* ] 



Multi-file searching 

Multi-file searching is now faster and gives you more options: 

• Faster THINK Pascal now searches through your files faster. 

• Specifying Folders You can specify in which folders THINK Pascal searches, in the 
dialog below. 


471 


















THINK Pascal User Manual 


• Find in All Files Command The Find in All Files command automatically opens all 
the files that contain the search string. Choosing the Find All Files command is like 
choosing the Find Next File command several times until you open all the files that 
contain your search string. To see the Find in All Files command, hold down the 
Option key and select the Search menu. 


Search files residing in: 


Akbar Programming THINK Pascal Folder 
Akbar .Programming THINK ...:Interfaces 
Akbar Programming THINK Pa... libraries 
Akbar .Programming THINK P... Cor e Files 
Akbar Programming Starter Folder' 




It 0K _J 

[ Cancel ) 


For more information, see “Searching in more than one file” in Chapter 6, “Editing.” 

Other new commands 

THINK Pascal contains these other new commands: 

• Quietly Auto-Reset If you’re running a program under THINK Pascal and you try to change 
your source files or the project, THINK Pascal displays a warning and asks if you want to cancel 
your change or reset the program. If this option is on, THINK Pascal won’t warn you and will 
automatically reset your program. This command is in the Debug menu. 

• Pull All Stops This command removes all Stop Signs from all the files in the project. To see this 
command, hold down the Option key as you select the Debug menu. 

• Get Info This command shows how much code and data each file in your project produces. It’s 
in the Project menu. It brings up this dialog: 



Runtime .lib 

k> 

Project Totals: 


Interface .lib 




PrintTraps.p 


Code: 59846 bytes 


Script.p 


Global Data: 2250 bytes 


Objlntf.p 


Jump Table: 6640 bytes 


EmbedDefProo.p 

jijijl 



PrintDialogs.p 


DialogUtils.p: 


ODIntf.p 


Code: 4588 bytes 


ODMDef s .p 




ODMenu.p 


Global Data: 10 bytes 


ODTDraw Window.p 


Jump Table: 272 bytes 


ODTList.p 




ODTPicWindow.p 




ODTShape.p 




ODT Window .p 

a 

II OK 1 

11- 

_ 



472 





What's New 


Enhanced THINK Class Library 

THINK Pascal 4.0 includes the THINK Class Library 1.1, which contains many new and improved 
classes, such as 

• Improved text-handling, including more Undo support and a styled text pane 

• System 7.0 support, including AppleEvents, aliases, and more 

• Improved error-handling 

• Larger panes, with 32-bit coordinates 

• Improved printing support 

• Multi-window document support. 

• Classes for dialogs, tables, and pop-up menus 

For more information, see the Object-Oriented Programming Manual, Chapter 7, “Using the THINK 
Class Library.” 

Other Changes 

THINK Pascal includes many other changes, including a faster compiler, larger limit on open 
windows, and an easier-to-use profiler. 

Faster compiler 

THINK Pascal 4.0 now compiles many projects faster, by as much as 20% to 30%. 

New limit on open windows 

You can now work with more open windows and documents at a time. THINK Pascal 4.0 lets you 
have up to 16 windows open, instead of 10. 

Easler-to-use profiler 

Profiling your code is now easier under THINK Pascal 4.0. You don’t need to add any function 
calls to your program to use the profiler. You just need to turn on the “Profile” option in the 
Compile Options... dialog. The profiler is also more accurate, measuring time in milliseconds, 
and lets you profile stand-alone applications. For more information, see Chapter 19, “The Profiler.” 





ANS Pascal Compatibility 

B 


Introduction 

This appendix describes the relationship between THINK Pascal and the requirements of 

ANSI/IEEE770X3.97-1983, American National Standard Pascal (ANS Pascal). (An American 

National Standard IEEE Standard Pascal Computer Programming Language (IEEE, Wiley- 

Interscience)) 

Topics covered in this appendix 

• Exceptions to ANS Pascal requirements 

• Extensions to ANS Pascal 

• Implementation-dependent features 

• Treatment of errors 

Exceptions to ANS Pascal Requirements 

THINK Pascal complies with the requirements of ANSI/IEEE770X3.97-1983 with the following 

exceptions: 

• In ANS Pascal, the special-symbol @ is an alternative representation for the special-symbol /N , 
and is required to be treated identically to ~ wherever it appears. In THINK Pascal, the special- 
symbol @ is an operator and is never treated identically to ~. 

• In ANS Pascal, identifiers may be of any length and all characters are significant. In THINK 
Pascal, all characters in identifiers are significant, but the largest identifier is restricted to 255 
characters. 

• In ANS Pascal, a character-string of length 1 is a char-type value and a character-string of length 
n is a value of a packed-string-type (a packed array [ 1. . n] of char — referred to as a 
string-type in ANS Pascal) with n components. In THINK Pascal, all quoted character-strings are 
string-type values. However, the compatibility and assignment-compatibility rules in THINK 
Pascal make its behavior with respect to character-strings compatible with ANS Pascal. 

• In ANS Pascal, all values of a tag type must appear once for a given variant part In THINK 
Pascal, this requirement is not enforced. 

• In ANS Pascal, a function block must contain at least one assignment statement assigning a 
value to the function identifier. In THINK Pascal, this requirement is not enforced. 

• In ANS Pascal, a field that is the selector of a variant part of a record may not be an actual 
variable parameter. In THINK Pascal, this requirement is not enforced. 


475 



THINK Pascal User Manual 


• In ANS Pascal, no statements that threaten the value of a control-variable of a for-statement are 
allowed. In THINK Pascal, this requirement is not enforced Changing the value of the control 
variable produces indeterminate results. 

• In THINK Pascal, the functions pack and unpack are not available. 

• In THINK Pascal, only the standard file variables input and output are allowed as program 
parameters. 

• In THINK Pascal, the range of integers is-32768. .32767 (-maxint-1. .maxint) 

• In THINK Pascal, the mod performs a simple remainder, not a true modulo operation. 

Note: There is no automatic means, in THINK Pascal, of determining whether or 
not a program violates any of the exceptions listed above. 


Extensions to ANS Pascal 

The following THINK Pascal features are extensions to Pascal as specified by ANSI/IEEE770X3.97- 
1983: 


Note: These extensions are described more fully in Appendix C, “Porting to 
THINK Pascal.” 

• The following are word-symbols in THINK Pascal: 

implementation otherwise 

inherited string 

inline unit 

interface uses 

object 

• An identifier may have an underscore appearing anywhere following the initial letter of the 
identifier. 

• THINK Pascal supports relaxation of the ordering of declarations. There may be any number of 
declaration parts in any order. 

• THINK Pascal supports the additional integer-type longint and the additional real-types 
double, computational, and extended. 

• A signed constant-identifier may denote a value of type integer, longint, or extended. 

• In THINK Pascal, the result of arithmetic performed on integer operands is integer. The re¬ 
sult of arithmetic performed on longint operands is longint. All mixed integer and 
longint operands are converted to longint before arithmetic is performed, and the result is 
longint. A longint value may be used wherever an integer value is required if the value 
falls in the range -maxint. .maxint. 



ANS Pascal Compatibility B 


• All integer-type and real-type operands are converted to extended before any real arithmetic is 
performed, and the result is always extended. An extended value may be used wherever a 
real, double, or computational value is required, provided the value falls within the 
range of values permissible. 

• THINK Pascal supports string-types, which are compatible with other string-types, packed- 
string-types, and char-type. 

• In THINK Pascal, the assignment-compatibility rules have been extended to allow the mixing of 
string-types, packed-string-types, and char-type where appropriate. 

• The result-type of a function is not restricted to simple and pointer-types; functions may return 
values of any type. 

• Individual char-type components of string-type variables and constants may be referenced as 
though the string were a one-dimensional array. 

• String-types may be compared with char-type and packed-string-type values. 

• The @ operator is provided for obtaining the address of a variable, procedure, or function. 

• THINK Pascal has an optional otherwise clause for the case-statement. 

• THINK Pascal supports the use of the indefinite-string-type, i.e. the word-symbol string, as a 
value or variable-parameter type. 

• An optional second parameter may be given to reset and rewrite to associate a file variable 
with an external file. 

• Instead of reset or rewrite, a file maybe opened with open to allow random read/write 
access to a file. 

• An explicit close procedure is supplied for those file variables associated with external files. 

• A seek procedure may be used for random-access to file components. 

• A f ilepos function returns the component number of the current file position, a value that 
may be used in subsequent seeks. 

• String-type and enumerated-type values may be read from textfiles with read and readln. 

• String-type and enumerated-type values may be written to textfiles with write and writeln. 

• Lazy I/O is used to permit interactive and non-interactive I/O to be treated identically. 

• In THINK Pascal, the ord function may be applied to a pointer-type value, facilitating address 
arithmetic. 


477 




THINK Pascal User Manual 


• The ord4 function is provided in THINK Pascal for converting an ordinal-type or pointer-type 
value to a longint. 

• The pointer function is provided in THINK Pascal for converting an integer-type value to a 
pointer-type value. 

• THINK Pascal includes a set of string procedures and functions. 

• The s i zeo f function is provided for obtaining the storage size of a variable or type. 

• Inline routines are supported for imbedding machine code in a program. 

• Units are supported for modular construction of programs and separate compilation. 

• THINK Pascal supports type-casting of values. 

• THINK Pascal supports all of the Macintosh Toolbox/OS constants, types, variables, procedures, 
and functions as predefined identifiers. 

• THINK Pascal supports Object Pascal extensions as described in Object Pascal Report , by Larry 
Tesler. Apple Computer 1985. 

• THINK Pascal allows constant expressions in const declarations. 

• THINK Pascal allows ranges for case labels. 

• THINK Pascal supports short circuit boolean operators & and I. 

• THINK Pascal supports the predefines cycle, exit, leave, and halt. 

Note: There is no automatic means, in THINK Pascal, of distinguishing between a 
program that uses extensions and one that does not. 

Implementation-Dependent Features 

The effect of using an implementation-dependent feature of Pascal, as defined by 
ANSI/IEEE770X3.97-1983, is unspecified as described in the preface to the Language Reference. 

Treatment of Errors 

This section defines those errors listed in Appendix D of the ANS Pascal standard that are not au¬ 
tomatically detected and reported by THINK Pascal. The number of each error listed below is the 
number under which the error is listed in the standard's appendix. The wording of the description 
of the error, however, differs from the wording in the standard. 

2. If t is the tag-field of a variant-part, and if f is a field within the currently active variant of that 
variant-part, then it is an error to attempt to alter the value of t while a reference to f exists. 



ANS Pascal Compatibility 


B 


4. If p is a pointer-type value, it is an error to reference p~ if the value of p is undefined. 

5. If p is a pointer-type value, it is an error to attempt to dispose of p while a reference to p~ 
exists. 

6. If f is a file-type variable, it is an error to attempt to close f or alter the current file position of 
f while a reference to f A exists. 

19. If a pointer-type variable p is assigned a value by new (p, , c 2 , • • ., c n ), it is an error to 

attempt to make any other variants than those selected by the case-constants in new become 
the active variant. 

20. If a pointer-type variable p is assigned a value by new (p, c 1 , c 2 , • . ., c n ), it is an error to 
attempt to dispose of p without supplying the same list of case-constants in the same order. 

21. Same as 20. 

22. Same as 20. 

24. It is an error to attempt to dispose of p if the value of p is undefined. 

25. If a pointer-type variable p is assigned a value by new (p, ci, c 2 , • • ., c n ), it is an error to 
reference the entire variable p~ in an expression, as an actual variable-parameter, or as the 
destination of an assignment-statement. 

37. For chr (x), the function returns a result of char-type which is the value whose ordinal num¬ 
ber is equal to the value of the expression x if such a character exists. It is an error if such a 
character value does not exist. 

38. For succ (x), the functions yields a value whose ordinal number is one greater than that of x, 
if such a value exists. It is an error if such a value does not exist. 

39. For pred (x), the functions yields a value whose ordinal number is one less than that of x, if 
such a value exists. It is an error if such a value does not exist. 

43. It is an error to reference a variable in an expression if the value of that variable is undefined. 

48. It is an error if the result of the activation of a function is undefined when that activation is 
complete. 

51. It is an error if none of the case constants is equal to the value of the case index upon entry to a 
case statement. 





Porting to THINK Pascal 


Introduction 

Pascal was designed by Professor Niklaus Wirth primarily as a tool for teaching systematic pro¬ 
gramming. It has evolved into one of the most popular programming languages, the main attraction 
being its emphasis on rigid structure and strong typing. In the evolution process most Pascal imple¬ 
mentations have a number of language extensions. Since most extensions are unique to an imple¬ 
mentation, you may need to do some work to port Pascal programs from one computer to another. 

Different implementations have interpreted the semantics of the unadorned language in different 
ways. This issue was addressed by the Joint ANSI/X3J9-IEEE Pascal Standards Committee, which in 
1982 approved a standard language (informally called ANS Pascal) to promote the portability of 
Pascal programs between implementations. 

THINK Pascal is intended to conform, as closely as possible, to ANS Pascal (see Appendix B), while 
providing extensions necessary for the development of serious Macintosh applications. THINK 
Pascal tries to keep such extensions to a minimum, choosing features common to many Pascal im¬ 
plementations, while retaining compatibility with existing systems, notably Macintosh 
Programmer’s Workshop (MPW) and Macintosh Pascal. 

This appendix is designed to help you port existing programs to THINK Pascal. It provides a com¬ 
prehensive list of areas in which THINK Pascal may differ from other implementations, along with 
suggestions for modifying programs to run under THINK Pascal. 

Topics covered in this appendix 

• Identifier length 

• Reserved words 

• Comments and directives 

• The uses clause 

• Types 

• Data representation 

• Data initialization 

• Operators 

• Integer arithmetic 

• Program parameters 

• Predefined procedures and functions 

• Standard units 

• Input/output 

• Run time environment 

• Extensions 

• Using . o files 


481 




THINK Pascal User Manual 


Identifier Length 

Most Pascal compilers only check the spelling of identifiers up to 8 or 1 6 characters. In THINK 
Pascal, all characters in an identifier are significant, up to the maximum length (255). For example, 
many compilers don’t report an error with this code: 

var 

aVe ryVe ryLongName: intege r; 

begin 

aVeryVeryLongNme := 0; 

end; 

THINK Pascal reports the misspelling as an undeclared identifier. 


Reserved Words 

THINK Pascal has added the following word-symbols which may not be used as identifiers: 


implementation 

inherited 

inline 

interface 

object 


otherwise 

string 

unit 

univ 

uses 


If you try to use one of these reserved words as an identifier, THINK Pascal reports an error. 


Comments and Directives 

Some Pascal compilers treat the comment delimiter pairs { } and (* *) differently, allowing 
comments which use one delimiter to be “commented out” with the other delimiter. For example, 
in MPW Pascal the code sequence 

if ResError <> noErr then {report resource error} 
alertStatus := Alert (MyRsrcAlert, nil); 

could be commented out like this: 

(* if ResError <> noErr then {report resource error} 
alertStatus := Alert (MyRsrcAlert, nil); 

*) 


THINK Pascal treats the different comment delimiter pairs the same, so you can’t nest comments. 
Also, comments may not cross line boundaries. THINK Pascal converts multi-line comments into 
several single line comments. Nested comments may not be converted correctly. 


482 



Porting to THINK Pascal 


C 


You can use the conditional compilation commands to comment out large blocks of code or to 
simulate multi-line comments like this: 

{$IFC FALSE} 

code to ignore 

{$ENDC} 

Compiler directives 

Most Pascal implementations support special compiler directive comments. These comments are 
typically of the form { $x+} or { $x-}, where x is a one or two character mnemonic for the par¬ 
ticular option. THINK Pascal supports a number of compiler directives; these are described in detail 
in Chapter 15. 

Compiler directives are not addressed in the ANS Pascal standard, so they vary greatly between 
implementations. For example, the MPW Pascal compiler supports: 

{ $i filename's include filename in text 

{$S segmentname } place code in segment segmentname 

{ $0V+} turn on overflow checking 

{ $R-} turn off range checking 

MPW also supports other compiler directives, most of which have no analog in THINK Pascal. It is 
best to assume that all compiler directives are not portable, and should be changed or removed. 

Note: You can enable and disable most of the THINK Pascal compiler directives 
from the Project window. 

THINK Pascal doesn’t support the {$1 filename } directive. However, when you turn on the “USES 
Extensions” option , you may be able to replace a {$1} directive in an MPW Pascal program with a 
uses statement in THINK Pascal. For more information, see Chapter 10, “Units and Libraries.” 

The Pascal Source Converter helps translate programs written for Apple’s MPW Pascal for use with 
THINK Pascal. It converts MPW Pascal directives to THINK Pascal directives, processes MPW Pascal 
$ I include directives, and more. For more information, see Chapter 20, “The Pascal Source 
Converter.” 

The Uses Clause 

Like many other Pascal compiler, THINK Pascal has a uses clause to specify the dependencies be¬ 
tween the files that make up a program. When your turn on the “USES Extensions” option in the 
Compiler Options... dialog, THINK Pascal interprets the uses clause differently from many other 
compilers. If your program must be compatible with one of these compilers, be sure to turn off the 
“USES Extensions” option. For more information, see Chapter 10, “Units and Libraries.” 


483 



THINK Pascal User Manual 


Types 

Different implementations of Pascal place different limitations on predefined and user defined da\a 
types. These limitations typically reflect the chosen representation of data, or constraints imposed 
by the underlying hardware architecture. For example, the ANS standard requires that the type 
integer contain all values in the range -maxint tomaxint, but accepts the fact that these 
values are machine dependent and may differ across implementations. 

THINK Pascal imposes the following data type limitations: 

• Integers are limited to the range -32768 to 32767. 

• Enumerated types may contain no more than 256 distinct values. 

You can declare array types larger than 32K, but the total size of all the variables in a block cannot 
exceed 32K. Suppose you wanted to create a large array. Here’s one way: 

type 

BigAry = array [0..99999] of integer; 

BigAryPtr = '"BigAry; 

BigAryHandle = '"BigAryPtr; 

var 

myBigAry : BigAry; { this is NOT allowed! } 

myBigAryH : BigAryHandle; { but this is } 

i : longint; 

begin 

myBigAryH := BigAryHandle(NewHandle(sizeof(BigAry))); 
for i := 0 to 99999 do 
myBigAryH'"'" [i] := 0; 

end; 

There are also areas in which THINK Pascal exceeds limitations imposed by other Pascal 
implementations. For example: 

• Support for the full set of integer including negative-value elements. 

• Support for floating-point values of single, double, computational and 
extended precision. 

• String-types, packed-string-types, and char-type are completely compatible. 

For a complete description of all THINK Pascal data types, refer to Section 3 of Chapter 17, 
“Language Reference.” 

Data Representation 

The way a Pascal compiler represents data depends on hardware differences and personal judg¬ 
ment. THINK Pascal follows the Macintosh Toolbox conventions for ordinal types. For example, 
the integer type is a 16 bit value to take advantage of the more efficient 16 bit instructions of the 


484 



Porting to THINK Pascal 


C 


MC68000. The 32 bit integer type longint is provided for dealing with values which exceed the 
range of 16 bit integers. 

The data type char is also implemented as a 16 bit (rather than the more natural 8 bit) value. It oc¬ 
cupies 8 bits only when packed. There are some subtle ramifications of this implementation. The 
predefined type text is usually assumed to have the same representation as file of char; 
Macintosh Pascal assumes that this is the case. In THINK Pascal, text has the same representation 
as packed file of char. This may cause difficulty when porting programs which use file 
of char. 

The representation of data in THINK Pascal is described more completely in Chapter 13, “Assembly 
Language.” 

Representation of packed records 

The different Pascal compilers for the Macintosh use different packing algorithms. For most packed 
records — including all those used by the Toolbox routines — the algorithms pack records the 
same way. The differences cause a problem only when you write a file of packed records with a 
program created with one compiler and try to read the file with a program created with the other 
compiler. 

If you must be certain that your data structures are the same between compilers, always specify 
dummy fields to pad out the unused bits. For example, this declaration creates a structure that 
looks the same, no matter which compiler you use: 

type 

Color = (Red, Blue, Green); 

Day = (Mon, Tue, Wed, Thu, Fri, Sat, Sun); 

MyPackedRecord = packed record 


w: 

Boolean; 

{ 

1 

bit 

} 

unusedl: 

0. .31; 

{ 

5 

bits 

} 

x: 

Color; 

{ 

2 

bits 

1 

unused2: 

0. .31; 

{ 

5 

bits 

} 

y : 

Day; 

{ 

3 

bits 

1 

z: 

Integer; 

{ 16 

bits 

} 


end; 

This record for that declaration looks like this: 


01_5 6 7 8_12 13_15 


1 w 

unusedl 

X 

unused2 

y 

0 




15 

z 


485 






THINK Pascal User Manual 


Data Initialization 

Some Pascal implementations guarantee specific values for uninitialized variables. For example, 
Macintosh Pascal initializes all global and local variables (and function results) to 0. THINK Pascal 
initializes only global variables to 0. Programs which (inadvertently) depend on other variables 
being initialized may run into unusual run-time behavior. 

Operators 

The implementation of operators in THINK Pascal conforms for the most part to the ANSI standard, 
differing only in areas where THINK Pascal provides additional data types (e.g. string, 
longint, extended). Porting difficulties may occur in expressions involving integer arithmetic 
overflow (see the following section). 

For compatibility with MPW Pascal and other Pascal compilers, THINK Pascal implements the mod 
operator as a simple remainder operator. 

Note: THINK Pascal 1.0 implemented the mod operator according to the rules for 
modulo arithmetic. 

Many compilers support an exponentiation operator ** for integer or floating-point operands. In 
THINK Pascal, floating-point exponentiation can be easily implemented, based on the following 
identity: 

x ** y = Exp (Ln (x) * y) 

If you port a program which uses integer exponentiation, you may have to write a simple 
exponentiation function. 

Integer Arithmetic 

THINK Pascal performs all integer arithmetic in either 16 bits or 32 bits depending on the type of 
the operands. For binary operators, if both operands are 16 bits (or smaller) the operation is per¬ 
formed in 16 bits; if either or both operands is 32 bits, the operation is performed Oess efficiently) 
in 32 bits. 

Consider the implications of these arithmetic rules on this piece of code: 

var 

i r j: integer; 

begin 

i := 20000; 
j := 30000; 
writeln (i+j); 

end; 


486 



Porting to THINK Pascal 


C 


This program fragment will cause an overflow error in THINK Pascal because the sum 20000+30000 
is too large to be represented in 16 bits. Other implementations (notably Macintosh Pascal) may 
perform the operation in 32 bits, avoiding the overflow at the expense of execution efficiency. You 
can force the arithmetic to be performed in 32 bits by casting the operands to longint or by using 
the Ord4 function. 

A similar problem arises in programs ported from Macintosh Pascal which use inline procedures 
and functions (inlineP, BlnlineF, WInlineF, LInlineF). The statement 

InlineP ($A9D1, 0+0, 65535, hTE); 

attempts to call TESetSelect with a longword 0 for selStart. In THINK Pascal, this results in a 
word 0 being pushed instead, misaligning the stack and (probably) resulting in a fatal error. You 
can cast the integer value to a longint. Statements like the one above are better replaced by a 
call to the equivalent Macintosh Toolbox routine: 

TESetSelect (0, 65535, hTE); 

This call performs the proper argument type checking and conversion, and it’s easier to understand 
and more efficient. 

Program Parameters 

THINK Pascal only allows the standard file-variables input and output as program-parameters. 
Occurrences of other file-variables in a program heading are reported as errors. These can be 
removed without affecting the semantics of the program. 

If you are porting code from a compiler that automatically opens up program parameters as file 
variables, you need to do a little rewriting. For example, if your program statement looks like this: 

program MyProgram (data, input, output); 

you have to rewrite it like this: 

program MyProgram (input, output); 

var 

data: text; 

begin 

open(data, 'data file'); 

close(data); 

end. 

Predefined Procedures and Functions 

THINK Pascal, like Macintosh Pascal, provides a large number of predefined procedures and func¬ 
tions in addition to those required by the standard. Routines have been added to facilitate address 


487 



THINK Pascal User Manual 


arithmetic, string handling, I/O, and other common tasks. On top of this, nearly all of the proce¬ 
dures and functions (and constants and types) described in Inside Macintosh are supplied as 
predefines (some are supplied as units: see below). 

Different implementations of Pascal are likely to provide different predefined procedures and 
functions, many of which have functional analogs in THINK Pascal. Programs that depend on non¬ 
standard predefines will require modification. For example, the following MPW Pascal predefines 
are not supported: 

fillchar 
mark 

moveleft 
moveright 

THINK Pascal also does not support the functions pack and unpack, which packs an unpacked 
array and unpacks a packed array. 

For a complete description of the THINK Pascal predefines, see §10 of Chapter 17, “Language 
Reference.” 


release 

scaneq 

scanne 


Toolbox Interfaces 

The interface files in the Interfaces folder are compatible with the latest from Apple . These are 
the interfaces discussed in Chapter 11. If you’re porting an older program over , you may need to 
change some of the interface files. In particular, 


If you used... 

Memtypes.p 
OSIntf.p 
Toollntf.p 
Packlntf.p 
MacPrint.p 
Pickerlntf.p 
SCSilntf.p 
Videolntf.p 


Now use... 

Types .p 

Files. p, Devices. p, etc. 

Windows . p, Menus . p, etc. 

Packages.p 

Printing.p 

Picker.p 

SCSI.p 

Video.p 


For more information on the THINK Pascal Toolbox interfaces, see “Calling Macintosh Toolbox 
Routines” in Chapter 11. 


Standard Units 

Pascal compilers for the Macintosh typically provide a standard set of units, libraries, or include 
files which define some or all of the constants, types, procedures, etc., described in Inside 
Macintosh , and whose declarations can be made available to any program or unit. For example, 
most MPW Pascal programs begin with the following uses clause: 

uses 

MemTypes, QuickDraw, OSIntf, Toollntf, Packlntf; 


488 



Porting to THINK Pascal C 


Similarly, Macintosh Pascal programs often start with: 

uses 

QuickDraw!., QuickDraw2; 

In THINK Pascal, most of the declarations in Inside Macintosh are predefined, and these uses 
clauses are not required. 

Note: You can use MemTypes, QuickDraw, OSIntf, Toollntf , and 
Packlntfif you add these files to your project. (They’re provided in your THINK 
Pascal package in either the Interfaces or Old Interfaces folders.) Most of 
these files contain no definitions. They’re included to make it easier to port from 
MPW Pascal. 

Some of the Inside Macintosh declarations, such as the AppleTalk Manager, are supplied as li¬ 
braries. Each is supplied as two files: a source (interface) file, and a library (code) file. Both of these 
files must be added to the project. The interface to the library is in the form of a unit The unit 
name must appear in a uses clause in the file that accesses the library. 

For more information on THINK Pascal’s Toolbox interfaces, see Chapter 11, “Using Predefined 
Routines.” The exact syntax for units is described in §8.3 of Chapter 17, “Language Reference.” 

Input/Output 

This is an area in which many Pascal implementations diverge, particularly in their treatment of in¬ 
teractive I/O. THINK Pascal supports I/O with ANS Pascal semantics and the following extensions: 

• An optional second parameter may be given to reset and rewrite to associate a file 
variable with an external file. A file opened with reset or rewrite is read-only or 
write-only respectively, and in both cases the file may only be accessed sequentially. 

• Instead of reset and rewrite, a file may be opened with open to allow random 
read/write access. 

• The seek procedure may be used for random-access to file components. 

• The f ilepos function returns the component number of the current file position, a 
value that may be used in a subsequent seek. 

• String-type and enumerated-type values may be read from text files using read and 
readln. 

• String-type and enumerated-type values may be written to text files using write and 
writeln. 

• Lazy I/O is used to permit both interactive and non-interactive I/O to be handled 
identically. 


489 



THINK Pascal User Manual 


THINK Pascal is identical to Macintosh Pascal in its treatment of I/O. Other compilers are likely to 
have different extensions. Programs which read and write to the predefined file variables input 
and output interactively may cause some difficulty; see Section 9 of Chapter 17, “Language 
Reference,” for a complete explanation of Lazy I/O and its ramifications. 


Run Time Environment 

Macintosh programs usually begin with a sequence of initialization calls to various portions of the 
Macintosh Toolbox. In THINK Pascal, the following initializations are performed automatically for 
your application: 

InitGraf (GthePort); 

InitFonts; 

InitWindows; 

InitMenus; 

TEInit; 

InitDialogs (nil); 

Set Appl Limit ( current value of A7 - Run Options ... stack size) ; 
for i := 1 to 10 do 
MoreMasters; 

If you initialize the Macintosh Toolbox manager explicitly in your program, use the { $1-} 
directive to turn off the automatic initialization (see Chapter 15, “Compiler Directives”). 


Extensions 

THINK Pascal supports several extensions to the Pascal language. 

Control procedures 

These procedures let you control the flow of your program without resorting to goto statements. 

cycle go to the next repetition of the enclosing while, repeat, or for 

statement 

leave go to the statement following the enclosing while, repeat, or 

for statement 

exit ( procname) exit the named (enclosing) procedure 

halt exit the program 

Constant expressions 

Constant expressions are allowed in const declarations. They must evaluate to a set, string-type, 
integer, char, boolean, or enumerated type. 


490 



Porting to THINK Pascal 


C 


Example: 

const 

limit = maxSize - 1; 

CR = Chr ($ OD); 

letters = ['a'.-'z', 'A'.-'Z']; 
digits = ['0'..'9 ' ]; 
alphanumerics = letters + digits; 

Case label subranges 

A case label in a case statement may be a range of constant values: 

case today of 

monday. . f riday : ... 

Saturday: ... 

Sunday: ... 

end; 

Generalized function results 

Function calls may be treated as simple variables or used as 1-values (variable-references appearing 
on the left-hand side of an assignment). 

Example: 

function InfoScrap: PScrapStuff; {a predefined Toolbox routine} 
external; 

var 

myHandle: Handle; 

begin 

myHandle := InfoScrap^.scrapHandle; 
with InfoScrap^ do 


Inside a function, be careful when you recursively call the function in an 1-value context. If the 
function name is qualified by the function is called recursively and the qualifier is applied to 
the return value. If the function name isn’t qualified or is qualified by or THINK Pascal 

assumes you are assigning the return value. For example: 

function Foo: Ptr; 

begin 

Foo := @Bar; { Makes @Bar the function's return value. } 

Foo A := 0; { Calls Foo recursively and assigns 0 to } 

{ the byte that the result points to. } 

end; 


491 



THINK Pascal User Manual 


Type casting 

Type casts may be applied to 1-values (variable-references appearing on the left-hand-side of an 
assignment, or as an actual var parameter) as well as r-values (variable-references appearing in 
expressions). For example: 

var 

myHandle: Handle; 
hTE: TEHandle; 
p: Point; 

begin 

myHandle := hTE AA .hText; 

CharsHandle(myHandle) AA [0] := Chr($0D); 

DrawChar (CharsHandle(myHandle) AA [0]) ; 

DisposHandle (myHandle); 

p := Point(0); 

Short circuit Booleans 

THINK Pascal uses the & and I operators for minimum evaluation of boolean expressions. In this 
statement: 

if (p <> nil) & (p A .name = '') then ... 

The second test (p A .name = 11 ) is performed only if the First test (p <> nil) evaluated to 
true. 

Using .o Files 

THINK Pascal can read . o Files, but it can’t use some . o Files made with high-level languages Oike 
MPW C or Pascal). These . o Files call routines in the compiler’s runtime library, even though there 
may not be explicit calls in the source code. These calls create link errors. For example, to handle 
operations on sets or 32-bit integers, most Pascal compilers call the runtime library. To avoid these 
problems, port . o Files created with C or Pascal by compiling the source code with THINK C or 
Pascal. 


Note: Assembly language is not a high-level language, so THINK Pascal can use a 
. o File created with it. 

For the same reason, other compilers can’t use some THINK Pascal libraries, even though THINK 
Pascal creates libraries in a . o-compatible form. 


492 



Error Messages 


Introduction 

This appendix is a guide to the error messages THINK Pascal generates. Compile, link, and the 
common runtime error messages, with their explanations, are arranged in alphabetical order. There 
are cross references to other chapters in this manual and examples of incorrect and correct code 
fragments. 

Error messages appear in an alert box, unless an error occurs while evaluating an expression in the 
Observe window. In that case, an abbreviated error message appears in the left cell of the Observe 
window. 

The examples have also taken advantage of THINK Pascal’s relaxation of order and number of 
declarations in a block. The examples assume that the following constants, types, and variables are 
defined:: 

const 

aConstant = 42; 
aCharConstant = 'c'; 
aStringConstant - 'hi there'; 

typo 

ColorType = (red, orange, yellow, green, blue, violet); 

WeightType = (LIGHT, MEDIUM, HEAVY); 
aType = integer; 

var 

aBool : boolean; 
aChar : char; 
anlnt : integer; 
aLong : longint; 
aReal : real; 
aDouble : double; 
anExt : extended; 
aString : string; 
aColor : ColorType; 

aPtr : Ptr; { Ptr is a predefined type } 

{ that points to SignedByte } 

ColorSet : sot of ColorType; 

TextFile : Text; 

FileOflnt : filo of integer; 

action will Reset your program. Continue anyway? 

While your program is running under the THINK Pascal environment, THINK Pascal stops running 
your program if you perform certain actions, including editing your program, modifying the 
project, closing the project, or quitting THINK Pascal). If you click Yes, THINK Pascal will continue 


493 



THINK Pascal User Manual 


the action and stop your program. If you click No, THINK Pascal will cancel the action and let your 
program continue running. 

“symbol ” Is already declared at this level. 

See 2.2.4 of Chapter 17. Example: 

var 

aDupName : integer; 

aDupName : real; { Error: aDupName already declared } 

typa 

recordType = record 

aDupName : integer; { OK:first time in the record } 

aDupName : real; { Error: already declared in record } 

end; 

procedure aDupName; { Error: already declared as a variable } 

begin 

end; 


procedure PI (aDupName:char); { OK: aDupName is not declared } 

{ at this level } 

begin 

end; 

procedure P2 (X:char; X:real); { Error: X declared twice } 

{ in parameter list } 

begin 

end; 


“symbol” Is not declared. 

• Check your spelling. Be careful to distinguish between 1 (one), 1 Gower case L), and 
I Cupper case i); and between 0 (zero) and O (oh). (Pascal is not case sensitive.) 

• Make sure the symbol is declared before it is used. 

• Make sure the symbol is visible at the level you are trying to use it. 

• If the symbol is in another unit, don't forget to use the unit name in a uses clause. 

In almost all cases, a name must be defined (or predefined) before it can be used. See Sections 3, 4, 
and 7 of Chapter 17. Example-. 

program HasUndeclaredSymbols; 

typo 

BadType = TypeYetToBeDefined; { Error } 

TypeYetToBeDefined = integer; { This must come before } 

{ the previous statement } 

RecPtrType = A RecType; { OK: a pointer type to a } 

{ type to be defined later } 

RecType = record 

PtrToARecord : A UndefinedType; { Error } 

PtrToNextRecord : RecPtrType; { OK } 
aField : integer; 

end; 


494 



Error Messages D 


var 

r : RecType; 
procedure Proc; 
var 

PrivateToProc : integer; 

begin 
end; 
begin 

PrivateToProc := 4; 

aField := 4; 
r.aField := 4; 

UndeclaredVariable := 4; 

UndeclaredProcedure; 
r.aField := UndeclaredFunc; 

end. 

“symbol ” Isn't In the current project, hasn't been successfully compiled, or Is In the 
wrong build order. 

When you use a unit, the unit must be compiled in the project. The unit being used must appear 
before the units that use when you see the project by build order. See Chapter 7 and §8.5 of 
Chapter 17. Example: 

unit anUnit; 
interface 

uses 

NonExistantUnit, UncompiledUnit, UnitFollowingThisOne; 

{ Error } 

implementation 

end. 

“ symbol ” looks like it's being used as a function, but It Isn't a function name. 

See 5.2 of Chapter 17. Example: 

program test; 
const 

x = 5; 

var 

i: integer; 

begin 

i : = x; { Correct } 

i := x(1); { ERROR } 

end; 


{ Error: PrivateToProc isn't } 

{ declared at this level } 

{ Wrong } 

{ Right } 

{ Error } 

{ Error } 

{ Error } 


495 



THINK Pascal User Manual 


“symbol ” looks like It's being used as a procedure, but It Isn't a procedure name. 

See 6.1.2 of Chapter 17. Example: 

typ« 

IntPtrType - A integer; 

var 

anlntPtr : IntPtrType; 
function Func : char; 
begin 
and; 

bagin 

aChar; 

aChar :« Func; 
anlntPtr :« pointer(aPtr) ; 
anlntPtr A := 3 

and; 

“symbol ” was previously declared as a function, not a procedure. 

When a function is declared in an interface part or as a forward function, it cannot be defined 
later as a procedure. See 7.1.1 and 8.1 of Chapter 17. Example: 

unit MisdefinedFunctions; 

intarfaca 

function InterfaceFunc : char; { To be defined in IMPLEMENTATION } 

implementation 

procedure InterfaceFunc; { Wrong: FUNCTION declaration expected } 

begin 

and; 

function InterfaceFunc; { Right } 

begin 

and; 

function ForwardFunc : char; { To be defined below } 

forward; 

procedure ForwardFunc; { Wrong: FUNCTION declaration expected } 

bagin 

and; 

function ForwardFunc; { Right } 

begin 

and; 

and. 


{ Error } 

{ Right } 

{ See §10.2.6 of Chapter 17 } 

{ Right: use temp variable anlntPtr } 


496 



Error Messages 


D 


“ symbol ” was previously declared as a procedure, not a function. 

When a procedure is declared in an interface part or as a forward procedure, it cannot be 
defined later as a function. See 7.1.1 and 8.1 of Chapter 17. Example: 

unit MisdefinedProcedures; 

interface 

procedure InterfaceProc; { To Be defined in IMPLEMENTATION part } 

implementation 

function InterfaceProc : char; { Wrong: PROCEDURE definition } 

{ expected } 

begin 

end; 

procedure InterfaceProc; { Right } 

begin 

end; 

procedure ForwardProc; { To Be defined below } 

forward; 

function ForwardProc : char; { Wrong: PROCEDURE definition } 

{ expected } 

begin 

end; 

procedure ForwardProc; { Right } 

begin 

end; 

end. 

<g> can only be applied to variable references, or to top-level procedure or function 
names. 

The address operator @ can only be applied to objects that actually have memory allocated to them. 
For example, constants, types, etc., do not allocate memory. Furthermore, @ cannot be applied to 
sub-level subroutines, because references to the variables in the outer scope cannot be set up 
properly. See 5.1.6 and 5.1.6.4 of Chapter 17. Example: 

program AtSigns; 

procedure Proc; 

procedure SubProc; 
begin 

aPtr := @Proc; { OK } 

aPtr :- @SubProc; { Error: SubProc is not } 

{ a top level procedure } 

end; 

begin { Proc } 
end; 
begin 


aPtr :- @anlnt; 
aPtr := @Proc; 

{ OK: memory is allocated for anlnt 
{ OK } 

} 

aPtr := SaConstant; 

{ Error: 

aConstant is 

a constant 

} 

aPtr :- @orange; 

{ Error: 

orange is an 

enumerated constant 

} 

aPtr :- @ColorType; 

{ Error: 

ColorType is 

a type 

} 

aPtr :- @integer; 

{ Error: 

integer is a 

type 

1 


end. 


497 



THINK Pascal User Manual 


@ can't be applied to a component of a packed type. 

@ cannot be applied to components of packed structures, because the actual data representation of 
a component in a packed structure may be different from that actual data representation in an un¬ 
packed structure. However, @ can be applied to the packed structure as a whole. See 5.1.6.2 of 
Chapter 17. 

@ can't be applied to predefined or Inline routines. 

The @ operator can only be applied to actual routines, not predefined, inline, or Macintosh Toolbox 
routines (which don't generate real subroutine calls). However, you can write a wrapper routine 
which wraps itself around the desired routine. Then, the @ operator can be applied to that wrapper. 
See 5.1.6.4 of Chapter 17. Example: 

procedure NOP; 

Inline 

$4e71; { M68000 NOP instruction } 

procedure WritelnWrap (s : string); 

begin 

writeln (s); 

end; 

procedure NOPWrap; 
begin 

NOP; 

end; 

function ButtonWrap : boolean; 

begin 

ButtonWrap := Button; 

end; 

begin 


aPtr 

:= ©writeln; 

{ Wrong: 

writeln is predefined procedure 

} 

aPtr 

©writelnWrap; 

{ Right: 

writeln is in a wrap routine 

1 

aPtr 

:= ©NOP; 

{ Wrong: 

NOP is an inline procedure 

} 

aPtr 

©NOPWrap; 

{ Right: 

NOP is in a wrap routine 

} 

aPtr 

:= ©Button; 

{ Wrong: 

Button is an Toolbox routine 

} 

aPtr 

:- ©ButtonWrap; 

{ Right: 

Button is in a wrap routine 

} 


end. 

Array Index type Incompatibility. 

The type of the expression that indexes an array must be compatible with the type of the index in 
the array declaration. See 4.3.1 of Chapter 17. Example: 

var 

ai : array[1..10] of char; 
aC : array [ColorType] of char; 

begin 

ai[4];»'a'; { OK: 4 is within 1..10 } 

ai[4 + anlnt]:='a'; { OK: type of (4+anInt) is } 

{ compatible with 1..10 } 


498 



Error Messages D 


ai[aReal]:='x'; { Wrong } 

ai[round(aReal)] : = 'x'; { Right } 

ai[aColor] : = 'x'; { Wrong } 

ai[ord(aColor)]:='x'; { Right: but why bypass strong typing? } 

aC[aColor]:='x'; { Right: Best } 

ai['c']:='x'; { Error } 

ai[4 + aReal]:='x'; { Error: type of 4+aReal is Real, not 1..10 } 

ai[succ(aColor)]: = 'x'; { Error: succ(aColor) is ColorType } 

ai[ai[anlnt]]:='x'; { Error: ai[anlnt] is char, not 1..10 } 

aChar:=aString[aChar]; { Wrong: string index must be 1..255 } 

aChar:=aString[ord(aChar)]; { Right } 

end; 

Array Index type is not Integer, char, enumerated, or subrange. 

See 3.2.1 of Chapter 17. Example: 

var 

Good_l : array [ ' A'. . ' Z'] of char; { OK: char subrange } 

Good_2 : array [ColorType] of char; { OK: enumerated type } 

Good_3 : array [1..10] of char; { OK: integer subrange ) 

Bad_l : array [real] of char; { Error } 

Assignment type incompatibility. 

You can’t put a square peg in a round hole. Pascal catches illogical statements that try to assign an 
expression of one type into a variable of an assignment-incompatible type. On occasion, this rule 
needs to be broken. The following examples show common errors and methods to break the rules. 
Use the methods at your own risk. Assignment compatibility can be subtle. See 3.5.3 and 5.4 of 
Chapter 17. Example: 

typ® 

CanonicalType = array [1..4] of char; { a type } 

IdenticalType = CanonicalType; { identical to CanonicalType } 

AnotherType = array [1..4] of char; ( a type DIFFERENT from } 

{ CanonicalType } 

var 

AnonArray : array [1..4] of char; { an array of anonymous type } 

CanonicalArray : CanonicalType; { a variable of a named type } 

IdenticalArray : IdenticalType; { a variable of a same type > 

AnotherArray : AnotherType; { a variable of a different } 

{ named type } 

AC : array [1..4] of char; 

PAC : packed array[1..4] of char; 

Rec : packed record 
i : integer; 

end; 

pint : A integer; 
pChar : A char; 

begin 

aString:=AC; { Wrong: can't assign UNpacked array of char } 

{ to strings } 

aString: =PAC; { Right: OK to assign pack array of char to strings } 


499 



THINK Pascal User Manual 


PAC:-aString; { Right: OK to assign strings to pack array of char } 

AC:-PAC; { Error: can't assign packed to unpacked array } 

anlnt:-aReal; { Wrong: Pascal doesn't convert float to integer } 

anlnt:-round(aReal); { Right: explicit conversion } 

anlnt:-trunc(aReal); { Right } 

aReal:-anlnt; { OK: Pascal converts integer to float } 

aReal:-3; { OK } 

aColor:-green; { OK } 

anlnt:-green; { Wrong: can't assign enumerated type to integer } 

anlnt:-ord(green); { Right: but why bypass strong typing? } 

aColor:- anlnt; { Wrong: can't assign integer to enumerated } 

aColor:-ColorType(anlnt); { Right: a CAST works but why } 

{ bypass strong typing? } 

AC:-Rec; { Error: can't assign totally different types} 

pInt:-pChar; { Wrong: can't assign different pointer types} 

pint:-pointer(pChar); { Right: a CAST works but why } 

{ bypass strong typing? } 

pint :- 7; { Wrong: can't assign a pointer a numerical value } 

pint A :- 7; { Right } 

CanonicalArray :- IdenticalArray; { OK } 

CanonicalArray :- AnotherArray; { Error: the types aren't } 

{ assignment compatible } 

CanonicalArray :- AnonArray; { Error: anonymous types are never } 

{ assignment compatible } 

and; 


At A-Trap 

This runtime message appears in the Observe window when the Break At A-Traps command is 
checked, and the expression being observed, directly or indirectly, calls a Macintosh Toolbox 
routine. See Chapter 14. 

At least one comment of more than 255 characters has been truncated to 255. 

THINK Pascal only supports comment lines which have fewer than 256 characters. 

At least one Identifier, literal string, or other token of more than 255 characters has been 
truncated to 255. 

THINK Pascal only supports identifiers, string literals, and other tokens which have fewer than 256 
characters. 


At least one valid constant declaration must follow CONST. 

See 1.7 and 2.1 of Chapter 17. Example: 

const 

BadConstant : false; { Wrong: Colon(:) instead of Equal(-) } 

GoodConstant - true; { Right } 

const 

{ Error: must have at least one CONST declaration } 

begin 

end; 


500 



Error Messages 


D 


At least one valid type declaration must follow TYPE. 

See 2.1 and 3 of Chapter 17. Example: 

typ« 

BadType : integer; { Wrong: Colon(:) instead of Equal(=) } 

GoodType = integer; { Right } 

typ« 

{ Error: must have at least one TYPE declaration } 

begin 

end; 

At least one valid variable declaration must follow VAR. 

See 2.1 and 4.1 of Chapter 17. 

var 

BadVariable = integer; { Wrong: « instead of : } 

GoodVariable : integer; { Right } 

var 

{ Error: must have at least one VAR declaration } 

begin 

end; 

Autointerrupt exception 

This runtime message is given when the programmer’s switch is hit, but a low level debugger 
(Macsbug or TMON) is not installed. This should only be used as a last resort. Since you cannot be 
sure of the state of your program, it may crash if you restart or reset it. Therefore, save all your files 
before continuing. It’s better to run with code compiled with the Debug Option (see Chapter 15) 
and click on the Bug Spray Can to stop, or always have a low level debugger installed. 

Available memory for variables declared at this level has been exhausted. 

Because of the MC68000 architecture, the local storage per function or procedure must not exceed 
32766 bytes. Similarly, the total global storage must not exceed 32766 bytes. Excessive global 
storage may not be detected until link time. 

In practice, even less storage may be available. Subroutines require local storage for all temporary 
variables generated by the compiler. For applications, QuickDraw globals are included in global 
storage. Furthermore, libraries may also require some global storage. 


501 



THINK Pascal User Manual 


If you need more memory, you must use storage allocation subroutines. See 10.1 and 10.2 of 
Chapter 17. For large data structures, the use of handles is highly recommended. See Inside 
Macintosh. THINK Pascal lets you declare types that are bigger than 32K, so it’s easy to use the 
Memory Manager to get huge arrays. 

program MemoryHog; 
const 

HalfTooBig = 16500; { The Max global size is about 32000 bytes } 

TooBig * 33000; 

typ® 

BigArrayType = packed array [0..HalfTooBig] of char; 

HugeArrayType - packed array [0..TooBig] of char; { OK } 

HugePtr * A HugeArrayType; 

HugeHandle = A HugePtr; 

var 

BigGlobalArrayl: BigArrayType; { OK } 

BigGlobalArray2: BigArrayType; { Error : Too much memory } 

{ Better: } 

BigArrayPtrl: A BigArrayType; { Allocate Pointers instead } 

BigArrayPtr2: A BigArrayType; 

TooBigArray: HugeArrayType; { Error: Way too big } 

{ Much Better] 

hTooBigArray: HugeHandle; { OK } 

procedure aProc; 
var 


BigLocalArrayl: packed array [0..HalfTooBig] of char; { OK } 

BigLocalArray2: packed array [0..HalfTooBig] of char; { Error } 

begin 

end; 

begin 

New(BigArrayPtrl); { Allocate memory } 

New(BigArrayPtr2); 

BigArrayPtrl A [ 15000] := 'c'; { Can access large array } 

{ with pointers } 


hTooBigArray := HugeHandle (NewHandle(sizeof(HugeArrayType))); { OK } 

hTooBigArray AA [33000] := 'z'; 

end. 


502 



Bad actual parameter for formal VAR, procedural, or functional parameter. 

See sections 7.3.2, 7.3.3, and 7.3.4 of Chapter 17. Example: 

procedure VarProc (var i : integer); 

begin 

end; 

procedure Proc (i : integer); 

begin 

end; 

procedure CalIP ( procedure P (i : integer)); 

begin 

end; 

function Func (c : char) : char; 

begin 

end; 

procedure CallF ( function F (c : char) : char) ; 

begin 

end; 

begin 


VarProc(anlnt +4); { Error: expressions can't be passed } 

{ as VAR parameters } 

VarProc(anlnt); { OK } 

CallP(Proc(3)); { Wrong: procedural parameters aren't } 

{ called with parameters ) 

CallP(Proc); { Right } 

CallF(Func('c')); { Wrong: functional parameters aren't } 

{ called with parameters } 

CallF(Func); { Right } 

end; 


Bad compiler directive 

You probably forgot something in a compiler directive 

program test; 
begin 

($SETC compiler_var = false} { Correct } 

{$IFC compiler_var} { Correct } 

writeln('This line will not be compiled.'); 

{$ENDC} 

{$IFC} { ERROR: missing expression } 

{$SETC} { ERROR: missing assignment } 

end. 

Bad decimal-places expression In WRITE, WRITELN, or STRINGOF call. 

The decimal-places expression is only valid for real output expressions and must evaluate to a 
positive integer expression. See 9.4.3.1, 9.4.3.2, 9.4.3.3, 9.4.3.4, 9.4.3.5, 9.4.3.6, and 9.4.3.7 of 
Chapter 17. Example-. 

writeln(anlnt : 7 : 3); { Error } 

writeln(aString : 7 : 3); { Error } 

writeln(aReal : 7 : aString); { Error } 


503 



THINK Pascal User Manual 


aString stringof(anlnt : 7 : 3); { Error } 

aString := stringof(aString : 7 : 3); { Error } 

Bad enumerated value. 

During runtime, the procedure read, readln, or readstring expected an enumerated value 
for a specific type, but did not get one. See 9.4.1.5 of Chapter 17. Example: 

readstring('paisley', aColor); { Error } 

readstring('plaid', aColor); { Error } 

readstring('violet', aColor); { OK } 

readstring ('yeLLOW', aColor); { OK: case not important } 

Bad expression type for READSTRING, or for READ or READLN from a text file. 

Text files and strings can only contain characters. Values that have a string representation (except 
for packed arrays of characters) can be read from a text file or extracted from a string. For example, 
an integer can be represented by a string of digits and can be read from a text file. On the other 
hand, a record cannot be read from a text file, because it is a collection of data which does not 
have a simple string representation. You might think it should be represented in a particular string 
format, but there are no rules for it in Pascal. 

Values that cannot be read from a text file, can be read from a file of that value's type. For ex¬ 
ample, an entire record can be read from a file of that record's type. If you really want to read 
a record from a text file or a string, then read each field of the record from the file or from string. 
See 9.4.1, 9.4.2, and 10.7.6 of Chapter 17. Example: 

typ« 

RecType * record 

Field_l : integer; 

Field_2 : char; 

end; 

var 

InString : string; { Input String that readstring reads from } 

TextFile : text; { Input that readln reads from } 

FileOfREC : file of RecType; 

IntPtr : ''integer; 

anArray : array[1..2] of char; 

PAC : packed array [1..6] of char; 

Rec : RecType; 
begin 

open(TextFile, 'text file'); 

open(FileOfREC, 'file of records'); 

readln(TextFile, aChar, aString, aColor, anlnt, aLong, aReal); {OK} 
readln(TextFile, IntPtr); { Wrong } 

readln(TextFile, aLong); { OK, but probably not } 

IntPtr pointer(aLong) ; { what you really want to do } 

readln(TextFile, IntPtr A ); { Right } 

readln(TextFile, anArray); { Wrong } 

readln(TextFile, anArray[1], anArray[2] ); { Right } 



Error Messages D 


readln(TextFile, Rec); { Wrong: can't read a record } 

{ from a text file } 

readln(FileOfREC, Rec); { Wrong: can't input a record } 

{ with a readln } 

read (FileOfREC, Rec); { Right: OK to read a record } 

{ from a file of records } 

readln(TextFile,Rec.Field_l,Rec.Field_2); { Right: OK to read fields } 

{ from TextFile } 

readstring(InString, aChar, aString, aColor, anlnt, aLong, aReal); 

(OK) 

readstring(InString, anArray); { Error } 

readstring(InString, Rec); { Error } 

end; 

Bad expression type for STRINGOF, or for WRITE or WRITELN to a text file. 

Text files can only contain characters . Values that have a string representation can be written to a 
text file or copied to a string. For example, an integer can be represented by a string of digits and 
can be written to a text file. On the other hand, a record cannot be read from a text file because it is 
a collection of data that does not have a simple string representation. You might think it should be 
represented in a particular string format, but there are no rules for it in Pascal. 

Values that cannot be written out to a text file can be written out to a file of that value's type. 
For example, a record can be written to a file of that record's type. If you really want to write a 
record to a text file, then write each field of the record to the text file or copy each field to a string. 
See 9.4.3, 9.4.4, and 10.7.5 of Chapter 17. Example: 

type 

RecType * record 

Field_l : integer; 

Field_2 : char; 

end; 

var 

IntPtr : A integer; 

anArray : array[1..2] of char; 

PAC : packed array[1..6] of char; 
aRec : RecType; 

FileOfREC : file of RecType; 

Result : string; 
begin 

open(TextFile, 'text file'); 
open(FileOfREC, 'file of records'); 
writeln(TextFile, aBool, aChar, aString, aColor, 
anlnt, aLong, aReal, PAC); {OK} 

Result :* stringof(aBool, aChar, aString, aColor, 
anlnt, aLong, aReal, PAC); {OK} 

writeln(TextFile, ord4(IntPtr)); { OK, probably not what } 

{ you really want to do } 

writeln(TextFile, IntPtr A ); { Right: outputs what IntPtr } 

{ points to } 

writeln(TextFile, anArray); { Wrong } 

writeln(TextFile, anArray[1], anArray[2]); { Right } 


505 



THINK Pascal User Manual 


write(TextFile, aRec); { Wrong: can't write a record } 

{ to a Text file } 

writeln (FileOfREC, aRec); { Wrong: can't output a record } 

{ with a writeln ) 

write (FileOfREC, aRec); { Right: OK to write a record } 

{ to a file of records } 

write(TextFile, aRec.Field_l, aRec.Field_2 ); { Also Right } 


writeln(ColorSet); { Wrong: can't write out a set directly } 

{ Right: find elements in set and print them ) 
for aColor :* red to violet do 
if aColor in ColorSet than 
write(aColor); 

Result := stringof(anArray); { Error } 

Result :* stringof(TextFile) ; { Error } 

Result :== stringof (aRec) ; { Error } 

end; 

Bad field-width expression In WRITE, WRITELN, or STRINGOF call. 

The field-width expression must evaluate to an integer expression greater than 0. Also, it is forbid¬ 
den to use field widths when writing to non-text files. See 9.4.3.1, 9.4.3.2, 9.4.3.3, 9.4.3.4, 9.4.3.5, 
9.4.3.6, and 9.4.3.7 of Chapter 17. Example: 


anlnt :« 7; 

writeln(anlnt : 1 + anlnt); { OK } 

writeln (anlnt : aString); { Error: field width expression } 

{ must be an integer } 

writeln(anlnt : aReal); { Error: field width expression } 

{ must be an integer } 

aString := stringof(anlnt : aString); { Error } 

aString :- stringof(anlnt : aReal); { Error } 

write(FileOflnt, anlnt : 4); { Wrong: can't specify field } 


{ width for non-text files } 

write(FileOflnt, anlnt); { Right } 

Bad Integer value. 

When reading a value from a text file into a variable, if the text cannot be converted to a value for 
the variable type, then this runtime error occurs. See 9.4.1, 9.4.1.1, 9.4.1.2, 9.4.1.3, 9.4.1.4,, 9.4.1.5, 
and 9.4.2 of Chapter 17. 

reset(TextFile, 'file containing ONLY letters'); 

readln(TextFile, anlnt); { Error: can't convert letters into integers } 

readln (TextFile, aString); { OK: any ASCII text can go into a string } 



Error Messages 


D 


Bad object type In method declaration 

The object type modifier in a method declaration is not an object name. 

program test; 

uaea 

Objlntf; 

type 

T - integer; 

procedure T.x; { ERROR: 'T' is not an object type } 

begin 

end; 

begin 

end. 

Bad pointer In DISPOSE. 

This runtime error most frequently occurs when you try to dispose an uninitialized or nil pointer or 
when you try to dispose the same memory twice. A less likely cause is that the heap is corrupted. 
This can happen if memory is used after it has been disposed. Use pointers with care. See 10.1.2 of 
Chapter 17. 

Bad real value. 

Your program attempted to read in a real value but found non-real characters instead. 

program test; 
var 

x: real; 
textfile: text; 

begin 

reset (textfile, 'reals'); 
while not eof(textfile) do 

readln(textfile, x); { ERROR when 'wxyz' is read } 

close(textfile); 

end. 


contents of file reals: 

12.3 

-12.3 

wxyz 

13 

Bad set constructor. 

See 5.3 of Chapter 17. 

ColorSet [[JJ; { Wrong: can't have a set of an empty set } 

ColorSet :- []; { Right: Empty Set } 


507 



THINK Pascal User Manual 


Bad SIZEOF parameter. 

The predefined function si zeof can only take variable or type names. (Note: the size of a string 
is not the same as its length, see 3.3 and 4.3.1 of Chapter 17). si zeof is described in 10.7.1 of 
Chapter 17. Example: 

type 

LongType - longint; { sizeof - 4 } 

var 

size : integer; 
stringl9 : string [19]; 
string20 : string [20]; 

pr2 : packed record { sizeof - 2 : packed chars are 1 byte apiece } 


cl, c2 : char; 

end; 

pr3 : packed record { sizeof - 4 : extra byte to align even word } 



cl, c2, 

c3 : char; 


end; 

ur2 

: record 

{ sizeof = 4 

: unpacked chars take up 2 bytes apiece } 


cl, c2 : 

char; 


end; 





arraylO : array[1..10] of integer; 
procedure aProcedure; 
begin 
end; 

function aFunction : boolean; 

begin 

end; 

begin 

size :« sizeof(anlnt + aLong); { Error: sizeof doesn't work } 

{ with expressions } 

size :« sizeof(aProcedure) ; { Error: sizeof doesn't work } 

{ with procedures } 


size 

: = 

sizeof (aFunction); 

{ Error: sizeof doesn't 

work 

} 




{ 

with functions 


} 

size 

:« 

sizeof(aConstant); 

{ Error: sizeof doesn't 

work 

} 




{ 

with constants 


} 

size 

: = 

sizeof (LongType); 

{ OK 

size = 4 


} 

size 


sizeof (stringl9); 

{ OK 

size - 20 


1 

size 

• = 

sizeof (string20); 

{ OK 

size = 22 


} 




{ 

1 len + 20 data + 

1 padbyte 

} 

size 

: = 

sizeof(pr2); 

{ OK 

size = 2 


} 

size 

: = 

sizeof (pr3); 

{ OK 

size = 4 


1 




{ 

pad byte to align 

even word 

} 

size 

: * 

sizeof (ur2); 

{ OK: 

: size * 4 unpacked 

chars 

} 




{ 

take up 2 bytes apiece 

} 

size 

: “ 

sizeof(arraylO); 

{ OK 

size = 20 


} 

size 

: = 

sizeof(size); 

{ OK 

size = 2 


} 

size 

: = 

sizeof (boolean); 

{ OK 

size = 1 


} 


308 





Error Messages D 


size := sizeof(char); 

size :« sizeof(integer); 
size sizeof(longint); 
size :« sizeof(real); 
size sizeof(double); 
size sizeof(extended); 

and; 

Boolean expression required. 

Boolean expressions are required in control statements and with boolean operators. See 6.2.2.1, 
6.2.3.1, 6.2.3.2, 5, and 5.1.3 of Chapter 17. Example: 

aBool := 3 or 4; { Error: the numbers 3 and 4 aren't booleans } 

if 3+4 than { Error: (3+4) doesn't evaluate to True or False } 

repeat 

until aReal; { Error: aReal doesn't evaluate to True or False } 

while green do { Error: green doesn't evaluate to True or False } 

/ 

Can’t convert .o file 

The MPW object file that THINK Pascal is trying to load contains some constructs that THINK 
Pascal can’t convert to its format. For instance, THINK Pascal cannot use MPW object Files that 
contain computed references or initialized data. 

Can’t EXIT procedure "procedure_name" from here 

The procedure name in an Exit statement must enclose the statement. 

program test; 

procadura proc; 
begin 

showtext; 

writeln('This will be written'); 

exit (proc); { CORRECT } 

writeln('This will not be written'); 

and; 

bagin 

proc; 

exit(proc); { ERROR: "proc" does not enclose this statement } 

and. 

Can't find the file “filename". Would you like to look for it? 

THINK Pascal remembers where a project's Files are by pathname. When this dialog box appears, 
the file is no longer where the project thinks it is. Either you have deleted the file or you have 
moved it to a new location. If you click OK and find the file, the project will remember its new 
location and ask you: 

Change “old location" to “new location" in all SUBSEQUENT (by build 
order) Project entries also? 


{ OK: size = 2, unpacked chars } 
{ take up two bytes } 
{ OK: size - 2 } 
{ OK: size - 4 } 
{ OK: size - 4 } 
{ OK: size - 8 } 
{ OK: size - 10 } 


509 



THINK Pascal User Manual 


THINK Pascal thinks if you have moved one file, so it is likely that you have moved other files too. 
As a convenience, you can change the references from the old location to the new location, but 
only by build order starting with files after the one you just changed. 

Can’t load a library with FAR relocations unless “Far Code” Is turned on In the “Set 
Project Type...” dialog. 

When the “Far Code” option in the Set Project Type... dialog is turned off, THINK Pascal cannot 
load THINK Pascal libraries which were built with the “Far Code” option on or . o files generated 
with MPW’s -model FAR option. 

Can't read Keyboard or Modem. 

This runtime error occurs when an expression in the Observe window tries to get input from the 
keyboard or modem. For example, the value cell of the Observe window will display this error 
when evaluating either of the following functions: 

var 

s : string; 
f : text; 

function ReadKeyBoard : integer; 
begin 

readln(s); 

ReadKeyboard := length(s); 

end; 

function ReadModem : integer; 

begin 

reset(f,'MODEM:'); 
readln(f, s); 

ReadModem := length (s); 
close(f); 

end; 

Case constant Incompatible with tag-type or selector expression. 

See 3.2.2 and 6.2.2.2 of Chapter 17. Example: 

type 

BadVariantRecordType = record 
case Tag : ColorType of 

red : ( {OK: red is a ColorType } 

i : integer; 

); 

15 : ( { Error: 15 is not a ColorType } 

j : real; 

); 

end; 


510 



Error Messages 


D 


begin 

case aColor of 

red : {OK: red is a ColorType } 

writeln('OK' ) ; 

15 : { Error: 15 is not a ColorType } 

writeln('Error') ; 

end 

end; 

Case constant needed here. 

See 6.2.2.2 of Chapter 17. Example: 

var 

aVariantRecord : record 
case boolean of 

: ( { Wrong: missing case constant before the colon (:) } 

i : integer 

) ; 

true : ( { Right: true is a valid case constant } 

c : char 

); 

end; 

begin 

case anlnt of 

writeln('Wrong: missing case constant before colon (:)'); 

2 : 

writeln('Right: 2 is a vaild case constant'); 

3. . 6 : 

writeln('Right: Subranges in Case List allowed '); 

3, 4 , 5, 6 : 

writeln('Right: 3,4,5,6 are valid case constants'); 
end; { of case } 
case anlnt of 

{ Error: at least one case constant required } 

end; { of empty case } 

end; 

Change “o/d location ” to “new location ” in all SUBSEQUENT (by build order) Project 
entries also?“ 

See the error message: “Can't find the file filename. Would you like to look for It?” 

Changing compile options will Reset your program. Continue anyway? 

See “actfon will Reset your program. Continue anyway?” 

Changing segmenatlon will Reset your program. Continue anyway? 

See “action will Reset your program. Continue anyway?” 

Changing segment attributes will Reset your program. Continue anyway? 

See “ action will Reset your program. Continue anyway?” 


511 



THINK Pascal User Manual 


I Changing the build order will Reset your program. Continue anyway? 

See “ action will Reset your program. Continue anyway?” 

Changing the “Far Code” switch will require that all files be recompiled or reloaded. Do 
you want to do this? 

When you changing the setting of the “Far Code” option in the Set Project Type... dialog, THINK 
Pascal must recompile all source files and reload all libraries. If you click Yes, THINK Pascal 
changes the setting of the “Far Code” option and removes all the object code from your project. If 
you click No, THINK Pascal returns you to the Set Project Type... dialog. 

Code segment n (name) is too large (actual size x bytes, limit Is y bytes) 

The code segment is too large and you must move files out of it. See “Segmenting a Project” in 
Chapter 7, “Working with Projects,” for more information. 

When you’re running a program under THINK Pascal, code segments must be 65,534 bytes or less. 
When you’re building a project, code segments must be 32,766 bytes or less, with one exception. If 
the “Far Code” option is one, the %_MethTables segment must be 65,534 bytes or less. 

Colon (:) required on this line or above. 

Colons are needed in labeled statements and case statements. See 3.2.2, 6.1.3, and 6.2.2.2 of 
Chapter 17. Example: 

procedure Proc; 
label 
1 , 2 ; 
begin 

goto 1; 

1 { Wrong: missing colon after the label 1 } 
writeln; 

goto 2; 

2 : { Right } 

writeln; 

end; 

end; 

Compiler variable is not defined 

Before you can use a compiler variable in a { $IFC } directive, you must define it. 
program test; 

{$SETC defined_var = false} { Definition of 'defined_var' } 

{$IFC defined_var} { Correct } 

{$ENDC} 

{$IFC undefined_var} { ERROR: 'undefined_var' is not defined } 

{$ENDC} 

begin 

end. 


512 



Error Messages 


D 


Component type of a file can't contain a file type. 

See 3.2.4 of Chapter 17. Example: 

typ® 

FileType - file of integer; 

Bad_NestedFileType - file of FileType; { Error: FILE OF a } 

{ file type } 

Bad_NestedFileRecordType - file of record 

F : FileType; { Error: FILE OF a type containing file } 

end; 

Bad_FileOfText - file of Text; { Error: Text is a file type } 

Constant expected. “ symbol ” Isn't a constant. 

At the erroneous statement, the compiler needs a constant to generate code for storage allocation, 
case statements, or variant records. See section 3 and 6.2.2.2 of Chapter 17. Example: 

var 

NotAConstant : integer; 

aBadString : atring[NotAConstant]; { Wrong } 

aGoodString : string[aConstant]; { Right } 

Bad : array [1..NotAConstant] of char; { Wrong } 

Good : array [1..aConstant] of char; { Right } 

bog in 

case anlnt of 

NotAConstant : { Wrong: case tags must be constants } 

writeln('Equal to NotAConstant'); 
aConstant : { Right: this case tags is constants } 

writeln('Equal to aConstant'); 

otherwise 

writeln('Otherwise something else') 

end; 

{ If you really want to have variable case tags, } 

{ use a series of else-ifs } 

if anlnt - NotAConstant then { Right } 

writeln('Equal to NotAConstant') 
else if anlnt - aConstant then { Right } 

writeln('Equal to aConstant') 

else 

writeln('Otherwise something else') { Right } 

end; 

Constant or expression (whose ordinal value Is Value) Is out of range. 

This compile time error is detected only when the Range compiler directive is on. See Chapter 15. 
Example: 

var 

a : array [1 .. 10] of 1 .. 6 ; 
r : real; 

Smalllnt : 1..10; 

Cool : green..violet; 


513 



THINK Pascal User Manual 


b«gin 

Smalllnt 11; { Error: 11 is too big for Smalllnt } 

Smalllnt 0; { Error: 0 is too small for Smalllnt ) 

Smalllnt :- 5 + 6; { Error: 11 is too big for Smalllnt } 

a[ll] :- 1; { Error: 11 is out of range for Index } 

a[10] :* 7; { Error: 7 is out of range for Element } 

writeln(r : -3); { Error: field width must be positive } 

writeln(r : 4 : 0); { Error: 2nd field width must be positive } 

Cool red; { Error: red is out of range for Cool. } 

{ ord(red) - 0 } 

Smalllnt :- 10; 


a[Smalllnt + 11] :- 1; { This error is not caught at compile time } 

end; 

Constant or type can't be defined In terms of Itself. 

See 1.7 and 3 of Chapter 17. Example: 


const 

aConst *» -aConst; { Error } 

type 

TheType - TheType; { Error } 

RecordPtrType “ A RecordType; { OK: type pointed to is } 

{ declared later } 

RecordType - record 

BadNextRecord: A RecordType; { Wrong: can't point to } 

{ defining type } 

NextRecord: RecordPtrType; { Rignt: must use previously } 

{ declared type } 

NestedRecord : RecordType; { Error: recursively nested } 

{ record } 

end; 


Constant value Is not numeric and must not have a sign. 

See 1.7 and 5.1.2 of Chapter 17. Example: 

const 

Dwarves - 7; 

MinusDwarves = -Dwarves; { OK } 

MinusRed - -red; { Error: red is non-numeric } 

MinusChar * —aCharConstant; { Error: non—numeric } 

Constant, expression, or packed type component was passed to a formal VAR 
parameter. 

When a parameter is passed to a formal var parameter, the called subroutine can modify the actual 
parameter passed. Therefore, constants and expressions cannot be passed as var parameters, 
because they cannot be changed. 

Components of packed structures cannot be passed as formal var parameters, because the actual 
data representation of a component in a packed structure may be different from the actual data 
representation in an unpacked structure. (For this Pascal implementation, only the representation 


514 



Error Messages D 


of packed and unpacked chars are different.) You can pass the entire packed structure as a var 
parameter. 

Note: The predefined procedures read, readln, and readstring are special 
because they can be passed components of packed records. See 7.3.2 of Chapter 
17. 

Example: 


typ* 

PackedArraylntType - packed array[1..4] of integer; 

var 

PackedRec : packed record 
il, i2 : integer; 

end; 

Rec : record 

il, i2 : integer; 

end; 

PackedAI : PackedArraylntType; 

AI : array [1..4] of integer; 
procedure Nextlnt (var i : integer); 

begin 

i := i + 1; 

end; 

procedure ChangePAI (var thePAI : PackedArraylntType ); 

begin 

end; 

begin 

Nextlnt (5); { Error } 

NextInt(anInt+5) ; { Error } 

Nextlnt(PackedRec.i2) ; { Wrong } 

Nextlnt(Rec.i2); { Right: works with an unpacked } 

{ record component } 

Nextlnt (PackedAI[2] ) ; { Wrong } 

Nextlnt(AI[2]); { Right: works with an unpacked } 

{ array component } 

ChangePAI(PackedAI); { OK: entire packed array can } 

{ be passed as a VAR parameter } 

readln (PackedAI[2]); { OK: readln works on packed } 

{ structures components } 


and; 


Control variable of FOR statement Is not of ordinal type. 

An ordinal type is one of integer, longint, char, or enumerated. See 3111 and 6.2.3.3 of Chapter 
17. Example: 


for aReal 1 to 10 do { Error: Reals are not ordinal } 

writeln('This will not work'); 
for anlnt :» 1 to 10 do { OK } 

writeln('anlnt anlnt); 

for aLong :- $10000 to $10020 do { OK } 

writeln('aLong =', aLong); 


515 



THINK Pascal User Manual 


for aChar :* 'a' to ' z' do { OK } 

writeln('The letters are aChar); 
for aColor :* violet downto red do { OK } 

writeln('The colors are aColor); 

CYCLE or LEAVE Is not In a loop 

You can use the Cycle and Leave procedures only in a for, while, or repeat loop. 

program test; 
var 

x: integer; 

begin 

for x 1 to 10 do 
begin 

writeln('This line will be written once.'); 
leave; 

writeln ('This line will not be written.'); 

end; 

for x := 1 to 5 do 
begin 

writeln (x : 1, ': This line will be written five times.'); 

cycle; 

writeln ('This line will not be written.'); 

end; 

cycle; { ERROR } 

leave; { ERROR } 

end. 

Data relocations not supported In Drivers and Code Resources. 

When you use a library from another compiler in a desk accessory, device driver, or code resource, 
you need to be careful about the data initializations in the library. THINK Pascal does not honor 
initializations that set a variable to be a pointer to a function or a pointer to another variable (that is, 
initializations that require runtime relocations). For example, THINK Pascal would not honor this 
initialization in a THINK C library: 

static ProcPtr myHook = &myFunction; 

But THINK Pascal would honor this initialization: 

char myString[] = "\psome string"; 

Divide by zero. 

An integer-type division resulted in a division by zero. If the division was floating point, the “SANE 
Floating Point Error” would occur instead. Example: 

anlnt anlnt div 0; 


516 



Error Messages 


D 


Division by zero attempted. 

Your program attempted to divide by zero. 

program test; 
var 

x: integer; 

begin 

x 5 div 0; { ERROR } 

x := 5 mod 0; { ERROR } 

end. 

Drivers, and code resources of an owner type must have a resource ID between 0 and 63, 
Inclusive. 

The Resource Manager requires these types of code segments have a resource ID between zero 
and 63: 


• Those owned by a driver. 

• Those Of type WDEF, CDEF, MDEF, PDEF, or PACK 

Duplicate case constant in this variant-part or CASE statement. 

Case constants must be unique within a case statement or record-variant. See 3.2.2 and 6.2.2.2 of 
Chapter 17. Example: 


typo 

BadVariantRecordType = record 


tag 

: 

integer of 

0 : 

( 

{ OK } 

); 

i 

: integer; 

0 : 

( 

{ Error: 

); 

r 

: real; 


end; 

begin 

case anlnt of 
2 : 

writeln ('two'); { OK } 

2 : 

writeln('twice'); { Error: 

end 

end; 


second 0 case } 


second 2 case } 


Editing will Reset your program. Continue anyway? 

See u action will Reset your program. Continue anyway?” 


517 



THINK Pascal User Manual 


END needed to complete the above record declaration. 

See 3 2.2 of Chapter 17. Example: 

procedure PI; 
type 

GoodRecordType = record 
aField : integer; 

end; 

BadRecordType = record 
aField : integer; 

begin 
end; 

END. Is required at the end of the file. 

You must have end . at the end of your file. Make sure all you begins are matched by ends. 

Execution halted. 

Statements in the Instant window and expression evaluation in the Observe window usually finish 
instantly (see Chapter 9). If they don’t, you can halt them by clicking on the Bug Spray Can. After 
halting the Instant window, THINK Pascal displays the message “Execution halted. ” After halting 
the Observe window, the message “Execution halted” appears in the value cell of the halted 
expression. 

Expression can't be cast to the specified type. 

When two variables are type-incompatible, they cannot be used interchangeably, even if they are 
the same size (as determined by sizeof). Casting bypasses this strong type-checking feature of 
Pascal. A cast changes a variable's type, but not its contents. For most casts, the two types must be 
of the same size. For example, on the MC68000 pointers and longints are type-incompatible, 
although both are 32 bits long. Type casting allows them to be used interchangeably. 

All casting is machine dependent and potentially dangerous. Use with caution. See 5.4 of Chapter 
17. Example: 

procedure Example sOf Casts; 

type 

LargeAType - array[1..1000] of integer; 

BigRType = record 

aComponent : LargeAType; 

end; 

SmallRType =» record 

aComponent : integer; 

end; 

Packed4Type = packed array[1.. 4] of char; 

TwolntType = array [1..2] of integer; 


{ Right } 

{ Wrong: Missing end for record declaration } 


518 



Error Messages D 


var 

Big : BigRType; 

Small : SmallRType; 
Packed4 : Packed4Type; 
Twolnt : TwolntType; 
Large : LargeAType; 

begin 


aLong :* longint(aReal); { Legal, BUT just copies bits, } 

{ doesn't convert to longint } 

aLong :« round(aReal); { This converts Real type to } 

{ equivalent Longint type. } 

aReal :« real(aLong); { Legal, BUT just copies bits, } 

{ doesn't convert to real } 

aReal aLong; { This converts Longint type to } 

{ equivalent Real type } 

aLong :« longint(Packed4); { OK: aLong and Packed4 are same size } 

Big := BigRType(Small); { Error: different sized records } 

Large := LargeAType (Big) ; { OK: Big and Large are the same size } 

Small SmallRType(Big); { Error: different sized records } 

anlnt := integer(Small); { OK : anlnt and Small are same size } 

Large :- LargeAType(Packed4); { Error: different size array } 

Twolnt :- TwolntType(Packed4); { OK: Twolnt and Packed4 } 

{ are the same size array } 

and; 


Expression must be constant 

THINK Pascal lets you declare constant expressions in your const declarations, but the expressions 
must be scalar— integer, boolean, char, or set. 


program test; 
var 

x: integer; 
const 

a - 1; 
b - 2; 
c = a + b; 

d = ( (a + b) * 2) div c; 

e — 3.2 + 2.8; { ERROR: 

f - (a + b) / c; { ERROR: 

g - a + b + x; { ERROR: 

begin 

end. 


{ Correct } 

{ Correct } 

constant expressions must be scalar 
(constant expressions must be scalar 
'x' is a variable 


} 

1 

} 


Expression too complex. 

Try simplifying your expression. Use temporary variables for intermediate results if necessary. 


519 



THINK Pascal User Manual 


Field name expected. “symbol ” Isn't a field of this record. 

See 4.3.2 of Chapter 17. Example: 

var 

NotAField : integer; 
rec_l : record 

field_l : integer; 

end; 

REC_2 : record 

FIELD_2 : integer; 

end; 

begin 


rec_ 

1.NotAField :- 0; 

{ Wrong: 

NotAField is not a 

field 

} 



{ 

of any record 


} 

rec 

1.field 1 := 1; 

{ Right 



1 

REC_ 

2 .field_l := 0; 

{ Wrong: 

field_l is a field 

of rec_l, 

} 



{ 

not of REC 2 


} 

REC_ 

2.FIELD_2 := 1; 

{ Right 



1 


end; 

File already open. 

A file-variable can only be used once per open file. See 9.2.3 of Chapter 17. Example: 

var 

NEWFILE, oldFile : Text; 

begin 

rewrite(NEWFILE, 'a new file'); 

open(NEWFILE, 'an old file'); { Wrong: file-variable NEWFILE } 

{ is already in use } 

open(oldfile, 'an old file'); { Right: use another file variable } 

end; 

File Is not open. 

This run time error occurs when any input or output operation is done using a file-variable that has 
not been previously opened or that is already closed. See 9.2.4 of Chapter 17. Example: 


var 

f : Text; 

TextFile : Text; 
begin 

close(f); 

rewrite(f, 'new file'); 
writeln(f, 'hello'); 
close(f); 
close(f); 


{ Error: file was not previously opened } 

{ OK } 

{ Error: file closed in previous statement } 


write(TextFile, anlnt); 
read(TextFile, anlnt); 
page(TextFile); { 

get(TextFile); { 

and; 


{ Error: TextFile was nenver opened 
{ Error 

Error: page does an implicit write to a file 
Error: get does an implicit read of a file 


) 

} 

} 

) 


520 



Error Messages 


D 


File Is not opened for random access. 

Only files opened with the procedure open are read-write. The procedure seek can be used only 
with read-write files. See 9.2.8 of Chapter 17. Example: 


rewrite(FileOfInt, 'new file'); 



seek(FileOflnt, 

0) ; 

{ Error 

} 

close(FileOflnt 

); 



reset (FileOflnt, 

•old file'); 



seek (FileOflnt, 

0) ; 

{ Error 

} 

close(FileOflnt 

); 



open(FileOflnt, 

•old file'); 



seek(FileOflnt, 

0); 

{ OK 

} 

close(FileOflnt 

); 




File Is not opened for reading. 

Files opened with rewrite are write only. See 9.3.1 and 9.4.1 of Chapter 17. Example: 

REWRITE(TextFile, 'WriteOnly File'); 
get(TextFile); { Error } 

read(TextFile, anlnt); { Error } 

readln(TextFile, anlnt); { Error } 

File Is not opened for writing. 

Files opened with reset are read-only, so you cannot write to them. See 9.2, 9.3.1, and 9.4.1 of 
Chapter 17. 

RESET(FileOfText, 'old file'); 
put(FileOfText) ; { Error } 

writeln (FileOfText, 'Error: cannot writeln to Readonly file'); 

FOR loop control variable modified 

Within a for loop, your program is not allowed to alter the value of the control variable. Use 
Cycle or Leave to alter control in the loop. 

for anint := 1 to d do 

anint := 5; { ERROR: can't modfiy control variable } 

FOR statement control variable must be a local variable. 

The Pascal language requires f or-loop control variables to be declared at the same level that they 
are being used. See 6.2.3.3 of Chapter 17. Example: 


program ForLoopControlVariables; 

var 

Outside : integer; { 

procedure SubProcedure (aParam : 

var 

local : integer; 

begin 

for integer := 1 to 10 do { 


can only be used in main program 
integer); 


Error: integer isn't a variable 


} 


} 


521 



THINK Pascal User Manual 


for aParam :* 1 to 10 do { Error: aParam isn't a local variable 

t 

for Outside :■ 1 to 10 do { Error: Outside isn't local variable 
for local :- 1 to 10 do { OK } 


} 

\ 


end; 

begin 

for Outside :* 1 to 10 do {OK: Outside is local to main program } 

/ 

end. 


Formal parameter type or result type should be a named type or STRING. 

When a type is used in a parameter list or in a function result declaration, it must be a named type. 
It cannot be an anonymous type, although this is allowed in a variable declaration. See 7.2 and 7.3 
of Chapter 17. Example: 


type 

ArrayType - array[1.. 2] of char; 

var 

Array_l : array[0.. 2] of set of char; 

Array_2 : ArrayType; 

function BadArray : array[1..2] of char; 

begin 

end; 

function GoodArray : ArrayType; 

begin 

end; 

type 

s25Type - string[2 5] ; 
function BadString25 : string [25]; 
begin 
end; 

function GoodString25 : s25Type; 

begin 

end; 

function Goodstring : string; 

begin 

end; 

type 

IntegerPtrType - A integer; 
function BadResult : A integer; 

begin 

end; 

function GoodResult : IntegerPtrType; 

begin 

end; 


{ OK: Array_l is of } 
{ an anonymous type } 
{ OK: Array_2 is of a } 
{ named type } 
{ Wrong } 


{ Right } 


{ Wrong } 

{ Right } 

{ Also Works } 


{ Wrong } 
{ Right } 


522 



Error Messages 


D 


{ Formal parameters must also have named types } 

procedure BadParam (p : A integer); { Wrong: A integer isn't named type } 

begin 

end; 

procedure GoodParam (p : IntegerPtrType); { Right } 

begin 

end; 

Formal value parameter can't be a file type or a type which contains a file type. 

For every open file, there must be only one copy of the file-variable. The operating system needs 
file-variables for file input/output. If a copy of the file-variable could be made and both were used 
for file I/O, then the file would be inconsistent. Therefore, passing a file-variable parameter by 
value (which makes a new copy) is forbidden. Passing a file-variable as a var parameter is 
permitted. See 7.3.1 of Chapter 17. 

typo 

IntFile « file of integer; 

RecWithFileType - record 
FileName : string; 

FileParameter : file of real; 

end; 

ArrayOfFileType - array [1..3] of file of integer; 


procedure Badl (F : IntFile); { Wrong: passing a filetype by value } 

begin 

end; 

procedure Goodl (var F : IntFile); { Right: pass it as VAR parameter } 

begin 

end; 

procedure Bad2 (R : RecWithFileType); { Wrong: passing a filetype } 

{ by value } 


begin 

end; 

procedure Good2 (var R : RecWithFileType); { Right } 

begin 

end; 

procedure Bad3 (A : ArrayOfFileType); { Wrong: passing a filetype } 

{ by value } 

begin 

end; 

procedure Good3 (var A : ArrayOfFileType); { Right } 

begin 

end; 


523 



THINK Pascal User Manual 


FORWARD or INTERFACE procedures or functions may not later be declared INLINE. 

See 7.1.3 of Chapter 17. Example: 

unit BadlnLine; 
interface 

function InterfaceFunc (x : char) : char; { INTERFACE declaration } 

implementation 

function InterfaceFunc; 

inline { Error: inline not permitted with INTERFACE } 

$4E71; { MC68000 NOP Instruction } 

procedure ForwardProc (x : char); { FORWARD declaration } 

forward; 

procedure ForwardProc; 

inline { Error: inline not permitted with FORWARD } 

$4E71; 

end. 


Function name required as an actual parameter to a formal functional parameter. 

Functional parameters are a way of passing functions as parameters. See 7.3.4 of Chapter 17. 
Example: 


function Func (i : integer) : integer; 

begin 

end; 

procedure Proc (i : integer); 

begin 

end; 

procedure CallF (function aFunc (i : integer) : integer); 

begin 

anlnt := aFunc(4); 


end; 

procedure RecallF (function aFuncParam (i : integer) : integer); 

begin 


CallF(Func); 

CallF(aFuncParam); 
CallF (4); 

CallF (Proc); 

end; 


{ OK: CallF is passed a function 
{ OK: CallF is passed a functional parameter 
{ Error: an integer is passed 
{ Error: a procedure is passed 


} 

} 

} 

} 


Global data exceeds max byte limit (size bytes). 

The total size of all the global variables in your project (size) exceeds the limit for your project’s 
type (max). These are the limits: 

If your project is its global data must be smaller than 

an application or a single-segment desk accessory 32K 

a multi-segment desk accessory 32K - the size of the jump table 

a code resource OK 


524 



Error Messages D 


If you need to create variables that require a lot of space, use the Memory Manager to allocate the 
space on the heap. Remember that THINK Pascal lets you declare array types that are bigger than 
32K. 

unit unitl; 
interface 
type 

BigArrayType = packed array [0..16500] of char; 

BAPtr = A BigArrayType; 

BAHandle = A BAPtr; 

var 

BigArrayl; BigArrayType; { one 16501-byte global variable } 

implementation 

end. 

program test; 

uses 

unitl; 

var 

BigArray2: BigArrayType; { another 16501-byte global variable } 

{ Error here. } 

BigArray3 : BAHandle; 

begin 

BigArray3 := BAHandle(NewHandle(sizeof(BigArrayType))); { OK } 

BigArray3 AA [16000] ;= 'x'; 

end. 

GOTO out of Observe/instant not allowed. 

Because of the special nature of Observe and Instant windows, non-local gotos, which directly or 
indirectly exit a subroutine’s current scope, are not allowed. For example, if you halted on the 
statement writeln; (see below) and then attempt to Observe the value of Escape, you will see 
this message in the value cell because of the goto 9999 statement. The goto 1 statement is a lo¬ 
cal goto and does not exit the Escape's current scope. Furthermore, normal execution of 
Escape within your program will work without error. 

program Escape; 
label 

9999; 

function Escape:integer; 

label 1; 
begin 

goto 1; {OK when Escape is called in Observe or Instant } 

anlnt 0; 

1: goto 9999; { Error when Escape is called in Observe or Instant } 

Escape := 42 ; { This statement is never executed } 

end; 


525 



THINK Pascal User Manual 


begin 

writeln('stop here'); 

anlnt Escape; { OK to call Escape within the program 1 

9999: 

end. 

Illegal Instruction Exception 

This runtime error indicates your program has run amok. For some reason, your program has 
jumped off into a random place in memory, or your code has been overwritten (e.g. by an uninitial¬ 
ized pointer), or the Memory Manager may be corrupted. Unless you can reproduce this behavior, 
it may be very hard to track down the problem and to fix it. You may have to use a low level de¬ 
bugger. (There are several bit patterns that are not legal MC68000 instructions. Your program was 
trying to execute one of these.) 

InitGraf's parameter must be @thePort. 

This runtime error occurs when the predefined Macintosh Toolbox call InitGraf is used with a 
parameter other than @thePort. This error is only detected while running with the THINK Pascal 
environment. See Inside Macintosh for more details. Example: 

InitGraf(@anlnt); { Wrong } 

InitGraf(@thePort); { Right } 

Insufficient stack space to invoke procedure or function. 

This runtime error occurs when a subroutine, compiled with the Debug compile option, deter¬ 
mines that there is not enough stack space remaining for it. It may be that too many nested subrou¬ 
tine calls have used too much stack space for local variables. However, your heap is probably un¬ 
harmed. The solution may involve fixing an out of control recursive subroutine or increasing your 
application’s stack size with the Run Options. .. command. Use LightsBug to examine the 
Subroutine Call Chain. See Chapters 13 and 15. Example: 

procedure EndlessRecursion(irlongint) ; 

begin 

EndlessRecursion(i+1); { Eventually, stack space will run out here } 

end; 

Integer overflow. 

The Overflow compile option inserts code that checks for intermediate arithmetic operation 
overflows. (See Chapter 15). This runtime error occurs when this check fails. Example: 

anlnt := 21000; 

anlnt := anlnt + 20000; { Error: the sum 41000 overflows anlnt, } 

{ resulting in the erronous value -24536 } 


526 



Error Messages 


D 


INTERFACE expected here. 

See 8.3 of Chapter 17. Example: 

unit MissingKeywordINTERFACE; 

{ Error: missing interface keyword here } 

implementation 

end. 


Invalid .o file 

The MPW object file THINK Pascal is trying to read is not in a format THINK Pascal understands. It 
may have been produced by the wrong version of MPW. 

Invalid formal parameter list. 

The parameter list in a function or procedure declaration is bad. See 7.3 of Chapter 17. Example: 


procedure BadProc_l (1, 2 : integer; { Wrong : bad parameter names 

ExtraSemiColon : integer; { Wrong : extra (;) after last 

) ; { parameter 

begin 

end; 

procedure GoodProc 1 (one, two : integer; { Right } 


LastParameter : 

) ; 

begin 

end; 

procedure BadProc_2 (x, y : 

INTEGER var z : char ) ; 

begin 

end; 

procedure GoodProc_2 (x, y : INTEGER; 

var z : char); 

begin 

end; 


integer { Right } 

{ Wrong: missing ; after 
{ INTEGER 

{ Right } 


} 

1 

} 


} 

} 


{ Wrong: aProc is declared as a procedure but has a result type CHAR } 
procedure BadCallF ( procedure aProc (i : integer) : CHAR); 
begin 

aProc(5); 

end; 

{ Right: aProc is correctly declared as a procedural parameter } 

procedure GoodCallP ( procedure aProc (i : integer)); 
begin 

aProc (5); 

end; 

{ Also Right: aFunc is correctly declared as a functional parameter } 
procedure GoodCallF (function aFunc (i : integer) : char); 

begin 

aChar := aFunc(5); 

end; 


527 



THINK Pascal User Manual 


Invalid INLINE constant. 

Only l6-bit integer values are allowed for inline constants. See 7.1.3 of Chapter 17. Example: 

{ Inline routine to Call a procedure through a pointer } 

procedure Wrong_JSR_To (PtrToProcedure: Ptr); 

inline { Wrong: constants must be word sized } 

$205F4E90; 

procedure Right_JSR_To(PtrToProcedure: Ptr); 

inline { Right: each constant is word sized } 

$205F, { MOVEA.L (SP)+,AO } 

$ 4 E 9 0; { JSR (AO) } 

procedure Proc; 
begin 
end; 

procedure Call; 
begin 

Right_JSR_To (@Proc) ; 

end; 

Invalid list of field names. 

Field names must be legal Pascal identifiers. See 1.2 and 3.2.2 of Chapter 17. Example: 

type 

InvalidFieldName = record 

Legal, 5, AnotherName : integer; { Error: 5 is bad field name } 

end; 

Invalid list of variable names. 

Variable names must be legal Pascal identifiers. See 4.1 of Chapter 17. Example: 

var 

a, 1, 2, c : integer; { Error: 1 and 2 aren't legal variable names } 

Invalid OBJECT typecast. 

You can cast an object only to an ancestor object. 

program test; 

uaea 

ObjIntf; 

type 

AnObj = object (TObject) 
end; 

AnotherObj = object (TObject) 
end; 

ExpandedObj = object (TObject) 
x, y, z: integer; 
function func: boolean; 

end; 


528 




Error Messages 


D 


function ExpandedObj.func: boolean; 

begin 

func := true 

end; 

var 

a, w: AnObj; 

b, x: AnotherObj; 

c, y: ExpandedObj; 

d, z: TObject; 

begin 

new(w); 
new(x); 
new(y); 
new(z); 


d 

= 

TObject(x); 

{ Correct 





} 

d 

= 

TObject(y); 

{ Correct 





} 

d 

= 

TObject(z) ; 

{ Correct, 

but z 

is already a 

TObject 

} 

c 

= 

ExpandedObj(x); 

{ ERROR 

if 

Range 

checking 

is 

on 

} 

c 

= 

ExpandedObj(z); 

{ ERROR 

if 

Range 

checking 

is 

on 

} 

b 

= 

AnotherObj(w); 

{ ERROR 

if 

Range 

checking 

is 

on 

} 

b 

- 

AnotherObj(y); 

{ ERROR 

if 

Range 

checking 

is 

on 

} 

b 

- 

AnotherObj(z); 

{ ERROR 

if 

Range 

checking 

is 

on 

} 


end. 

Invalid PROGRAM parameter list. 

See 8.2 of Chapter 17. 

Invalid redeclaration of method 

You’ve tried to declare a field of an object as a method. 

program test; 

uses 

Objlntf; 

type 

TestObj =■ object (TObject) 
x: integer; 

end; 

procedure TestObj.x; { ERROR: 'x' is a field, not a method } 

begin 

end; 

begin 

end. 


529 





THINK Pascal User Manual 


Invalid result type In function declaration. 

See 7.2 of Chapter 17. Example: 

function BadFl; { Wrong: missing result type } 

begin 

end; 

function GoodFl : char; { Right } 

begin 

end; 

function BadF2 (c : char)char; { Wrong: missing colon in result type } 

begin 

end; 

function GoodF2 (c : char) : char; { Right } 

begin 

end; 

function GoodF3 : char; { OK: forward definition of GoodF3 } 

forward; 

function GoodF3; { OK: definition of forward function may leave off } 

begin { its result type } 

end; 

{ Wrong: missing result type for formal functional parameter "aFunc" } 
procedure BadCall (function aFunc (c : char)); 
begin 
end; 

{ Right } 

procedure GoodCall (function aFunc (c : char) : CHAR); 

begin 

end; 

Invalid variable, field, or formal parameter list. A colon (:) might be missing. 

When a variable name is declared, a corresponding type must be provided. See sections 3 and 4 of 
Chapter 17. Example: 

var 

VariableWithoutAType; { Wrong: missing type } 

Variable : integer; { Right } 

aRecord : record 

FieldWithoutAType; { Wrong: missing type } 

GoodField : integer; { Right } 

end; 

procedure P (aParamWithoutAType; { Wrong: missing type } 

aGoodParam : integer); { Right ) 

begin 

end; 


530 



Error Messages 


D 


Invalid variant declaration. 

See 3.2.2 of Chapter 17. Example: 

type 

BadVariantRecordType = record 
case i : integer of 
1 : ( 

a, b : char; { OK } 

) ; 

2 : ( 

{ Right: OK to have empty variant } 

) ; 

3 : 

; { Wrong: Missing () for empty variant } 

end; 

Jump Table exceeds 32K limit [size bytes) 

See “The jump table is too large.” 

Label has already been declared. 

See 2.2.4 of Chapter 17. Example: 

program BE_70; 
label 

6 ; 

procedure SubProc; 
label 

6; { OK: This label is in a different scope } 

procedure SubSubProc; 

label 

6; { OK: This label is in a different scope } 

label 

6; { Error: duplicate label declaration in SubSubProc } 

begin 

6: 

/ 

end; { SubSubProc } 

begin 

6: 

9 

end; { SubProc } 

begin 

6: 

end. 


531 



THINK Pascal User Manual 


Label has already been used to label a statement. 

See 2.2.4 of Chapter 17. Example: 

procedure Proc; 
label 

13; 

begin 

13 : 

writeln('OK'); 

13 : 

writeln('Error: another statement with a label 13 at this level'); 

end; 

Label has not been used to label any statement. 

Labels must label a statement at the level where the label is declared. See 2.1 of Chapter 17. 
Example: 

program UsingLabels; 
procedure Zero; 
label 

0; { Error: label is not used in procedure which declared it } 

begin 

writeln; 

end; 

begin 

end. 


Label hasn't been declared at this level. 

Statements can only be labeled with labels declared at the same level. See 2.1 and 6 of Chapter 17. 
Example: 

program UsingLabels; 

label 

1 ; 

procedure Z e roAndOne; 
label 

0 , 1 ; 

begin 

0 : 

/ 

1 : 

9 

end; { ZeroAndOne } 


532 




Error Messages 


D 


begin 

13 : { Error: 13 was never declared } 

writeln ('Statement Labeled with 13'); 

0 : { Wrong: 0 was not at this level } 

writeln ('Statement Labeled with O'); 

1 : { Right: irrelevant if 1 was declared in ZeroAndOne } 

writeln ('Statement Labeled with 1'); 

end. 

Label was not declared at the same level as this statement. 

Statements can only be labeled with labels declared at the same level. See 2.1 of Chapter 17. 
Example: 

program UsingLabels; 

label 

1,2; { declares labels for use in main program } 

procedure SubProc; 

begin 

1 : { Wrong: label 1 hasn't been declared at this level } 

goto 2; { OK to GOTO a label at an outer scope } 

end; { SubProc } 

begin 

1 : { Right: label 1 must be used at this level } 

writeln('statement labeled with 1'); 

2 : { Right: label 2 must be used at this level } 

writeln('statement labeled with 2'); 

end. 

Library must contain at least one file. 

When you use the Build Library... command, the project must contain at least one file. See 
Chapter 10. 

Library must contain only one code segment. 

The project you are trying to build into a library contains more than one segment. Before you can 
build it, you must either (1) combine the segments into a single segment or (2) break up your pro¬ 
ject into multiple single-segment projects and build a library for each project. To see how your 
project is segmented, click on the view control in the upper right corner of the project window. See 
Chapters 7 and 10. 

Library must not contain a main program. 

Libraries are not allowed to have a main program. 

Link Failed: multiply-defined: “symbol ” 

• Have you included two different versions of the same library into your project? 

• Does a library contain an extraneous Runtime . lib or Interface . lib? 

Link Failed: undefined: “symbol ” 

• Have you added all necessary libraries to your project? 

• Have you declared a subroutine external and never defined it in one of your libraries? 


533 



THINK Pascal User Manual 


Lower boundary of subrange Is greater than upper boundary. 

For types, the lower bound must be less than the upper bound. For set constructors, the lower 
bound can be greater than the upper bound, in which case the set is empty. See 3.1.1.3 and 5.3 of 
Chapter 17. Example: 

procedure Proc; 
var 

BadColor : blue..red; 

BadSubrange : 3..1; 
aSet : set of ColorType; 

begin 

aSet := [blue..red]; 

end; 

Macintosh System Error: -nnn 

One of the more obscure Macintosh errors has occurred. See Inside Macintosh. 

Macsbug/TMON not Installed 

Your program tried to execute a Debugger or DebugStr procedure when a low level debugger 
wasn’t installed. 

program test; 
begin 

Debugger; { ERROR if no low-level debugger is installed } 

DebugStr('Break in TEST');! ERROR: same reason } 

end. 

MC68881: divide by zero 
MC68881: Inexact 
MC68881: not a number 
MC68881: operand error 
MC68881: overflow 
MC68881: underflow 

You’ll get these errors only when you have the 68881/68882 option on (see Chapter 15) and you’ve 
enabled halts for certain conditions. (See the SetHalt routine in the Apple Numerics Manual^) 


{ Error } 

{ Error } 

{ OK: aSet is empty } 


534 



Error Messages 


D 


Method not found. 

The method you tried to invoke doesn’t exist for the object you’re using. 

program test; 

u sos 

Objlntf; 

typ® 

AnObj = object (TObject) 
procedure proc; 

end; 

procedure AnObj.proc; 

begin 

end; 

var 

T: TObject; 

A: AnObj; 

begin 

new (T); 

a := AnObj(T) ; 

a.proc; { ERROR } 

end. 

Method not inherited by this object 

You used the inherited keyword in front of a method name, but the object you’re referencing 
doesn’t inherit that method. 

program test; 

uses 

Objlntf; 

type 

AnObj = object (TObject) 
end; 

AnotherObj = object (AnObj) 

function func: boolean; 

end; 

function AnotherObj.func: boolean; 

begin 

func true; 

end; 
var 

x: AnotherOb j; 
b: boolean; 

begin 

new (x) ; 
b := x.func; 
with x do 

b := func; 

with x do 

b := inherited func; 

end. 


{ Correct } 
{ Correct } 
{ ERROR } 


535 



THINK Pascal User Manual 


Missing or Invalid unit name In this USES. 

See 8.1 of Chapter 17. Example: 

program WithBadUSES; 

uses 

4; { Error: invalid unit name } 

begin 

end. 


NIL dereference. 

The Range compile option inserts code into your program which checks for nil pointer derefer¬ 
ences (see Chapter 15). This runtime error occurs when this check has failed. Sometimes the actual 
cause of this error is long gone from the scene, but often the culprit is close at hand. You may be 
able to find the problem using Observe and LightsBug. 

Note: If the pointer is not initialized before assignment, then you probably will 
not get this error. Instead, some piece of memory may be corrupted. Later, an Odd 
Address or an Illegal Instruction may occur. 

Example: 


{ Assumes the Range compile option is On } 

var 


IntPtr : A integer; 

begin 

IntPtr := nil; 
IntPtr A := 13; 
IntPtr @anlnt; 
new(IntPtr); 

IntPtr A 13; 

end; 


{ It's important to initialize Pointer Variables! } 
{ Wrong: IntPtr is a NIL pointer } 
{ This makes sure that IntPtr points to something } 
{ Also makse sure that IntPtr points to something } 
{ Right: IntPtr now points somewhere } 


No context 

This message appears in the value cells of the Observe window when your program is not running, 
paused, or halted. Because there is no program context, expressions (even constants) cannot be 
evaluated. 


No windows are available for opening your file. 

You can open up to eight edit windows to edit files. This number does not include the Instant and 
Observe windows. If you get this message, you’ll need to close some files. Remember that THINK 
Pascal doesn’t close files when you click on a window’s close box. You need to use the Close 
command in the File menu to close a file. You can also hold down the Command key as you click 
in the window’s close box. 


536 



Error Messages D 


Not previously declared as a method 

You’re trying to define a method that you didn’t include in the object’s declaration. 

unit unitl; 
interface 

uses 

Objlntf; 

type 

TestObj = object (TObject) { Declare object type "TestObj" } 

function func: boolean; { Declare method "TestObj.func" } 

end; 

implementation 

function TestObj.func: boolean; { Implementation of method } 

{ "TestObj.func" } 

begin 

func true 

end; 

procedure TestObj.proc; { ERROR: this method wasn't declared } 

{ in the declaration of TestObj } 

begin 

end; 

end. 

Objects and Methods may not be declared In nested scopes 

Objects and methods must be defined in the outermost scope. Procedures and functions cannot 
define objects or methods. 

program test; 

uses 

Objlntf; 
procedure proc; 
type 

TestObj = object (TObject) { ERROR: trying to declare object } 
end; { within scope of "proc" } 

begin 

end; 

begin 

end. 


537 



THINK Pascal User Manual 


unit unitl; 
interface 

uses 

ObjIntf; 
procedure proc ; 
type 

TestObj - object (TObject) { Object "TestObj" ) 

function func: boolean; { Method "TestObj.func" } 

end; 

ispleznentation 

procedure proc; 

function TestObj.func: boolean; { ERROR: can't declare method } 

begin { within scope of "proc" } 

end; 

begin 

end; 

end. 

Operand type Incompatibility. 

Some operations aren’t allowed, though it seems they ought to be. For example, record assign¬ 
ments are legal because it is easy to do a blind byte copy. However, record comparisons are for¬ 
bidden, because a blind byte comparison will not work, and anything else is too hard. In particular, 
two equivalent structures can have different bit patterns because of byte padding or different 
garbage in inactive variants. The solution is to write your own comparison functions for records 
and arrays. (Note: it is permitted to compare packed arrays of characters.) 

The following examples show common errors and methods to break the rules. Use the methods at 
your own risk. See 3.5 and 5 of Chapter 17. 

var 

AC1, AC2 : array[1..10] of char; 

PAC1, PAC2 : packed array[1..10] of char; 

PAI1, PAI2 : packed array[1..10] of integer; 

Reel, Rec2 : packed record 
IntFieldl : integer; 

CharField : char; { byte of pad between IntFieldl and IntField2 } 
IntField2 : integer; 

end; 

ptrl, ptr2 : ptr; 

stringl, string2, string3 : string; 


begin 

stringl := string2 + string3; { Wrong } 

stringl := concat(string2, string3); { Right: see 10.5.3 of } 

{ Chapter 17 } 

aBool :- (aReal <> anlnt); { OK to compare real with integer } 

aBool :- (aString <> AC1); { Wrong: can't compare strings with } 

{ UNpacked char array } 

aBool :« (aString <> PAC1) ; { Right: OK to compare strings with } 

{ packed char array } 

anlnt :- 3.5 mod 4.5; { Wrong: MOD can't take real arguments } 


538 



Error Messages 


D 


anlnt := 3 mod 4; { Right } 
aColor red + blue; { Wrong: can't use + on enumerated types } 
aColor := ColorType(ord(red)+ord(blue)); { Right: BUT is this } 

{ really meaningful? } 
aBool :- (ptrl > ptr2); { Wrong: ptrs have no ordering } 
aBool :- (longint (ptrl) >longint (pt r2) ) ; { Right: BUT is this } 

{ really meaningful?} 
aBool := (ptrl <> ptr2); { OK: can only use - and <> on ptrs } 
AC1 :- AC2; { OK: it's legal to assign unpacked arrays } 
aBool := (AC1 <> AC2); { Wrong: can't use <>, etc. } 

{ on unpacked char arrays } 
aBool := (PAC1 <> PAC2); { Right: OK to compare packed CHAR array } 
aBool :« (PAC1 > AC1); { Error: can't compare packed and } 

{ unpacked CHAR array } 
aBool :- (PAI1 <> PAI2); { Error: can't compare packed arrays } 

{ of NonChars } 
Reel :- Rec2; { OK to assign records } 
aBool :- (Reel « Rec2); { Error: can't compare records this way } 

and; 


OVERRIDE expected 

If you want to redefine a method that belongs to an ancestor object, you need to use the 
override directive. 

program test; 

uses 

Objlntf; 

type 

AnObj = object (TObject) 

function func: boolean; 

end; 

AnotherObj = object (AnObj) 

function func: boolean; 

end; 

function AnObj.func: boolean; 

begin 

func := true 

end; 

function AnotherObj.func: boolean; 

begin 

func :« false 

end; 
begin 
end. 


{ OK method "AnObj.func" } 

{ Error: need "override" if re- } 

{ defining method } 


539 



THINK Pascal User Manual 


Parameter list doesn't match previous declaration 

THINK Pascal lets you repeat the parameter list for procedures and functions defined in the inter¬ 
face section or for routines declared forward The parameter lists must match exactly. Note that 
parameters of type string do not match. You must create a type for them. 

unit unitl; 
interface 

procedure proc (x, y, z: integer); 

inplementation 

procedure proc (x, y, z: longint); { ERROR: type should be "integer" } 

begin 

end; 

end. 

Period (.) required following the last END of the file. 

See 8.1 of Chapter 17. Example: 

program MissingPeriod; 

begin 

end { Error: Missing period } 

Predefined and inline procedure names can't be used as procedural parameters. 

Predefined, Toolbox, or inline calls (which aren’t genuine subroutines) cannot be passed as proce¬ 
dural or functional parameters. However, you can write a wrapper routine (which wraps itself 
around the desired subroutine) that you can pass as a procedural or functional parameter. See 7.3.3 
of Chapter 17. Example: 

program ProceduralAndFunctionalParameters; 

procoduro CallF (function F (e : Extended) : integer); 

begin 

end; 

procedure CallP ( procedure P) ; 

begin 

end; 

procedure NOP; 
inline 

$4e71; { M68000 NOP instruction } 

procedure NOPWrap; 

begin 

NOP; 

end; 

function TruncWrap (e : Extended) : integer; 

begin 

TruncWrap := Trunc (e); { Predefined function } 

end; 

procedure OpenRgnWrap; 

begin 

OpenRgn; 

end; 

begin 

CallF(Trunc); { Wrong: Trunc is predefined function } 

CallF(TruncWrap); { Right: Trunc is called from TruncWrap } 


540 



Error Messages D 


CallP(NOP); { Wrong: NOP is an inline procedure } 

CallP(NOPWrap); { Right: NOP is called from NOPWrap } 

CallP(OpenRgn); { Wrong: OpenRgn is a Toolbox procedure } 

CallP(OpenRgnWrap) ; { Right: OpenRgn is called from OpenRgnWrap } 

end. 

Printer port In use by AppleTalk. 

You will have to use the modem port instead If you really want to use AppleTalk, see Inside 
Macintosh and Chapter 11. 

Procedure name required as an actual parameter to a formal procedural parameter. 

See 7.3.3 of Chapter 17. Example: 

function Func (i : integer) : integer; 

begin 
end; 

procedure Proc (i : integer); 

begin 
end; 

procedure CallP ( procedure aProc (i : integer)); 
begin 

aProc(4); 

end; 

procedure RecallP ( procedure aProcParam (i : integer)); 

begin 

CallP(Proc); { OK: CallP is passed a procedure } 

CallP(aProcParam); { OK: CallP is passed a procedural parameter name } 

CallP (4); { Error: an integer is passed } 

CallP (Func); { Error: a function is passed } 

end; 

Procedure or function has a FORWARD declaration but was never defined. 

The subroutine declarations that use the forward directive allow you to defer the subroutine's 
definition. However, the definition must appear later in the file. See 7.1.1 and 8.3 of Chapter 17. 
Example: 

unit aUnit; 
interface 
implementation 

procedure aForward; { Error: never defined later in this unit. } 
forward; 

end. { end of unit } 

PROGRAM or UNIT Is missing from the beginning of this file. 

Y ou must have the keyword program or unit at the beginning of your file. 

Project has no main program. 

In order for your program to run, a file which contains a main program needs to be added to your 
project. The file should contain the program keyword. 

541 



THINK Pascal User Manual 


Quitting will Reset your program. Continue anyway? 

See “ action will Reset your program. Continue anyway?” 

READLN and WRITELN can only be used with text files. 

The predefined procedures readln and writeln only work with text files. Use read, write, 
put or get for all other types of files. See 9.3 and 9.4 of Chapter 17. Example: 

procedure Proc; 
var 

FileOfChar : file of char; { not the same thing as text } 

PackedFileOfChar : packed file of char; { not the same thing as text } 

FileOflnt : file of integer; { not at all the same as text } 

begin 

open(TextFile, 'Text File'); 

writeLN(TextFile, 4); { OK } 

readLN(TextFile, anlnt); { OK } 

open(PackedFileOfChar, 'packed file of CHAR'); 
writeLN(PackedFileOfChar, 'a') { Wrong } 

write(PackedFileOfChar, 'a'); { Right } 

readLN(PackedFileOfChar, aChar); { Wrong } 

read(PackedFileOfChar, aChar); { Right } 

open(FileOfChar, 'file of CHAR'); 

writeLN(FileOfChar, 'a') { Wrong } 

write(FileOfChar, 'a'); { Right } 

open(FileOflnt, 'file of INTEGERS'); 
writeLN(FileOfInt, 4); { Wrong } 

write(FileOfInt, 4); { Right } 

and; 

Record contains no fields. 

Records must contain at least one field. Example: 

type 

RecordType = record 

and; { Error: no fields } 

Record name expected. “ symbol ” Isn't a record. 

Symbol is not properly used in a record reference. See 6.2.4 of Chapter 17. 

type 

RecordType = record 

aField : integer; 

end; 

RecordPtrType = A RecordType; 

var 

aRecord : RecordType; 
aRecordPtr : RecordPtrType; 
function aFunc : RecordPtrType; 

begin 

end; 


542 



Error Messages D 


begin 

anlnt.aField := 3; 
aRecord.aField := 3; 
with anlnt do 

aField := 3; 
with aRecord do 
aField := 3; 
new(aRecordPtr) ; 
aRecordPtr.aField:=3; 
aRecordPtr A .aField:=3; 

end. 

Replacing will Reset your program. Continue anyway? 

See u action will Reset your program. Continue anyway?” 

Replacing a file in the project will Reset your program. Continue anyway? 

See u action will Reset your program. Continue anyway?” 

Result can't be assigned to the function named “ symbol ” outside of its declaration. 

See 7.2 of Chapter 17. Example: 

program AssigningToFunctions; 

typ® 

IntPtrType = A integer; 

var 

IntPtr : IntPtrType; 
function aFunction : integer; 

begin 

aFunction := 42; { Right } 

end; 

begin 

aFunction := 42; { Error: outside of function declaration } 

end. 

Result type doesn’t match previous declaration 

You can repeat the result type of a function you previously declared forward, but the result types 
must match exactly. Example: 


function GregHowe : char; 
forward; 

function GregHowe : integer; { ERROR: Result type must be char } 

function GregHowe : char; { OK: Result type matches } 

function GregHowe; { OK: OK to leave out result type } 

{ if previously declared forward } 


{ Wrong: anlnt is not a record } 

{ Right } 

{ Wrong: anlnt is not a record } 

{ Right } 


{ Wrong: need to dereference pointer } 
{ Right: the A makes all the difference } 


543 



THINK Pascal User Manual 


unit unitl; 
interface 

function PaulVetri: integer; 

inclement ation 

function PaulVetri: longint; { ERROR: type should be "integer" } 

begin 

PaulVetri:= 13; 

end; 

end. 

SANE Floating Point Error 

A SANE (Standard Apple Numerics Environment) call has resulted in an error. Note: a Floating 
point division by zero results in this error, while an integer-type division by zero results in the 
Divide by zero error. Example: 

var 

r: rea1; 
i: integer; 

begin 

r := 10.2; 

for i := 1 to 11000 do 
r := r * 10; 

end; 

SEEK and FILEPOS are only allowed for disk flies. 

You'cannot use the SEEK and FILEPOS routines on devices like the modem port. 

program test; 
var 

textfile: text; 
position: longint; 

begin 

open(textfile, 'old file'); 
seek(textfile, 0); 
position := filepos(textfile) ; 
close(textfile); 
open(textfile, 'MODEM:'); 
position := filepos(textfile) ; 
seek (textfile, 0); 

end. 

SEEK of a negative component number not allowed. 

See 9.2.8 of Chapter 17. Example: 

open(FileOfInt, 'old file'); 

seek (FileOfInt, -1); { Error } 

seek(FileOfInt, 0); { OK: seeks to first component in file } 

seek(FileOfInt,maxlongint); { OK: seeks to last component in file } 


{ Correct } 
{ Correct } 


{ ERROR: textfile is the MODEM: } 
{ ERROR: textfile is the MODEM: } 


544 



Error Messages D 


Segment Loader error (not enough memory). 

When a subroutine in an unloaded segment is called, the segment loader automatically loads it into 
the heap. This error will occur when there is not enough memory to load the segment. You can ei¬ 
ther increase your Heap size with the Run Options Command. .., or use UnloadSeg to unload 
unneeded segments. See Inside Macintosh. If you’re running with MultiFinder, increase the size of 
THINK Pascal’s partition. 

Selector expression of CASE statement Isn't of ordinal type. 

See 3.1.1 and 6.2.22 of Chapter 17. Example: 

begin 

case aReal of { Error: aReal is not ordinal } 

3.14159 : 

end 

case ColorSet of { Error: ColorSet is not ordinal } 

[red] : 

/ 

end 

case anlnt of {OK: anlnt is ordinal } 

0 : 

end; 

case aChar of {OK: aChar is ordinal } 

•c’ : 

f 

end; 

case aColor of {OK: aColor is ordinal } 

red : 

end; 

case aLong of {OK: aLong is ordinal } 

$40000 : 

end; 

end; 

Semicolon (;) or END expected after the previous statement. 

See 6.2.1 of Chapter 17. Example: 

begin 

writeln('Error: Missing Semicolon at end of this line 
writeln('OK: Semicolon not needed at end of this line') 

end; 


545 



THINK Pascal User Manual 


Semicolon (;) or UNTIL expected after the previous statement. 

See 6.2.3.1 of Chapter 17. Example: 

begin 

repeat 

writeln('OK') ; 
until false; 

repeat 

writeln ('Error: missing semicolon on this line —>') 
writeln 
until false; 

repeat 

writeln ('Error: Missing UNTIL'); 

end; 

Semicolon (;) required on this line or above. 

See 2.1, 1.7, 3, 4.1, 7.1,7.2 of Chapter 17. 


label 


0 

{ Error: 

missing 

semicolon 

at 

end 

of 

line 

} 

const 

BadConstant = 0 

{ Error: 

missing 

semicolon 

at 

end 

of 

line 

} 

type 

BadType - char 

{ Error: 

missing 

semicolon 

at 

end 

of 

line 

} 

var 

BadVar : integer 

{ Error: 

missing 

semicolon 

at 

end 

of 

line 

} 

procedure BadProc : CHAR; 

{ Error: 

procs do not return values 


} 

begin 

end; 

function BadFunc : char 

{ Error: 

missing 

semicolon 

at 

end 

of 

line 

} 


begin 

end; 

Set constant out of range 
Set value out of range. 

When assigning a value to a set, the range of the resulting set expression must be within the range 
of variable’s set type. Example: 

var 

DigitSet : set of 0..9; 

WarmSet : set of red..yellow; 

begin 


DigitSet 

:= [-1, 11; 

{ Error: -1 not in 

range 

0. . 9 

} 

DigitSet 

:- [S..10]; 

{ Error: 10 not in 

range 

0. . 9 

} 

DigitSet 

:= []; 

{ OK } 




DigitSet 

:= [ 0..9]; 

{ OK } 




DigitSet 

:= [1, 2, 3, 5, 71; 

{ OK } 




if 1000 in DigitSet then 

{ OK: even if 1000 

isn't 

in range 0..9 

} 


546 



Error Messages 


D 


DigitSet := DigitSet - [10..15]; { OK: expression is in range } 

WarmSet [blue]; { Error: blue not in range red. .yellow } 

WarmSet :=[];{ OK } 

WarmSet :- [red..yellow]; { OK } 

and; 

Set elements must be Integer, char or enumerated. 

Set element types are limited. However, in THINK Pascal the ranges are not as limited as in other 
Pascal implementations. See 3.2.2 of Chapter 17. Example: 

typ® 

ArrayType - array[1..3] of integer; 

RecordType = record 

aField : integer; 

end; 

SetType - set of char; 

var 

SetOfArray : set of ArrayType; { Error } 

SetOfLongint : set of longint; { Error } 

SetOfRecord : set of RecordType; { Error } 

SetOfReal : set of real; { Error } 

SetOfSet : set of SetType; { Error } 

SetOf Color : set of ColorType; { OK } 

SetOfChar : set of char; { OK } 

SetOfSmallInts : set of 1..10; { OK } 

SetOfintegers : set of integer; { OK } 

Stack has moved Into application heap. 

The stack has overflowed into the heap; the heap is probably damaged. This error, which may be 
more familiar as System Error ID 28, is not always detected. (See Inside Macintosh .) In hindsight, 
you should have compiled with the Debug option, which probably would have caught this error 
safely and in time. (See Chapters 7 and 15.) 

String constant must have length 1 to be compatible with Char. 

See 3.5.3 of Chapter 17. 

const 

aStringConstant = 'Hi'; 

NullStringConstant = ' ' ; 

CouldBeEither = •?•; 

begin 

aChar :- ' ' ; 

aChar :- NullStringConstant; 
aChar :- 'Hi'; 
aChar :- 'C'; 
aChar :- CouldBeEither; 

end; 


{ Error } 
{ Error } 
{ Error } 
{ OK } 

{ OK } 


547 




THINK Pascal User Manual 


String constant too large or too small for destination 

When assigning a string constant to a string variable, the string constant must fit. When assigning a 
string constant to a packed array of characters, the length of the string constant must be the same as 
the number of characters in the array. Example: 

var 

s5: string [5]; 


PAC5 

packed array [1 

.5] of 

char; 







begin 










s5 : - 

'twelve chars'; 

{ 

Error: 

length 

of 

string 

constant 

> 5 

} 

s5 : - 

•five!'; 

{ 

OK } 







PAC5 

= 'twelve chars' 

{ 

Error: 

length 

of 

string 

constant 

<> 5 

} 

PAC5 

= 'four'; 

{ 

Error: 

length 

of 

string 

constant 

<> 5 

} 

PAC5 

= 'five!'; 

{ 

OK } 








and; 


String range error. 

Do not confuse a string's size with its length. This runtime error is caused by accessing a character 
element of a string with an index outside the range 1. . length (aString). If you need to 
lengthen a string, use the insert procedure or include function. See 3.3, 4.3.1, and 10.5 of 
Chapter 17. Example: 

var 

a: integer; 
s : string[8 ] ; 

begin 

s := 'abcdefgh'; 
for a : a 1 to 9 do 
writeln(s[a] ) ; 

and; 

aString := 'foo'; 
aString[3] 'u'; 

aString[4]:= ' r' ; 
insert('r', aString, 4); 

String size must be a number between 1 and 255. 

See 3.3 of Chapter 17. Example: 

var 

aStringFloating : string [3.4]; { Wrong: string size not an integer } 

aString256 : string[256]; { Wrong: string size > 255 } 

aStringMinusOne : string[-l]; { Wrong: string size < 1 } 

aString5 : string [5]; { OK } 


{ OK: current length of aString is 3 } 
{ Wrong: can't append to string this way } 
{ Right: aString = 'four' } 


548 




Error Messages 


D 


String too large. 

If a string is being read into by a read, readln, or readstring statement, the destination string 
must be big enough to accommodate the result. See 9.4.1.4 of Chapter 17. 

var 

aString5 : string [5]; 

begin 

readstring('The input string has more than 5 chars', aString5); 

{ Error } 

end; 

Subrange boundaries are not of the same type. 

Two constants in a subrange definition must have compatible types. See 3.1.1.3 of Chapter 17. 
Example: 


var 

SubrangeOfDifferentTypes : red..HEAVY; 
GoodSubRange : red..yellow; 

BadSet : set of red..HEAVY; 

GoodSet : set of red..blue; 

AlsoGoodSet : set of ColorType; 


{ Wrong } 

{ Right } 

{ Wrong } 

{ Right } 

{ Also Right } 


Subrange boundary is not integer, char, or enumerated. 

See 3.1.1.3 of Chapter 17. 


type 

BadRealType = 2.5..3.1; { Error: real in subrange } 

{ is not allowed } 

var 

RealSubrange : 2.5..3.1; { Error: real in subrange } 

{ is not allowed } 


Subrange error. 

The Range compile option inserts code which checks for out of range errors in your program (see 
Chapter 15). This runtime error occurs when this check has failed. Example: 

var 

Small : 1. . 5; 

Big : -20000..20000; 

begin 


anlnt 

6; 



Small 

:= anlnt; 

{ Error 

} 

Small 

anlnt - 3; 

{ OK } 


anlnt 

:« 30000; 



Big :* 

anlnt; 

{ Error 

} 


end; 


549 



THINK Pascal User Manual 


Superclass type must be object 

The heritage of an object must be another object. If you declare objects whose superclass is 
TOb ject, don’t forget to add Ob jlntf. p to your project. 

program test; 

usas 

ObjIntf; 

typo 

TestObj = object (TObject) { CORRECT } 

end; 

BadTestObj = object (integer) { ERROR: integer isn't an object } 

end; 

begin 

end. 

Tag type must be ordinal. 

See 3.1.1 and 3.2.2 of Chapter 17. 

type 

BadVariantRecordType - record 

case FloatingPointTag : Real of 

3.1416 : ( { Wrong: tag type can't be Real } 

Pi : string[2] 

); 

end; 

GoodVariantRecordType = record 


caso i 

: integer of 

3 : ( 

{ Right } 

Pi 

: string[2] 

); 



end; 

OKVariantRecordType - record 
case longTag : longint of 

$12345 : ( {OK: tag type can be Longint } 

L : string [8] 

); 

end; 

The entire read will be re-executed when you continue. 

If you click on the Bug Spray Can while reading from the Text window with read or readln, the 
read will stop and all pending input will be thrown away. When you continue the program, the 
entire read will be started over again. 


550 



Error Messages 


D 


The jump table Is too large (actual size x bytes, limit is y bytes) 

The jump table is too large. If you didn’t turn on the “Far Code” option in the Set Project Type... 
dialog , try turning it on. 

If “Far Code” Is... and you are The jump table limit Is 

off running under THINK Pascal 65,534 bytes 

off building an application 32,766 bytes 

on running under THINK Pascal 262,144 bytes 

on building an application 262,144 bytes 

For more information on the “Far Ccode” option, see “Building applications with large jump tables” 
in Chapter 12, “Building Projects.”. 

The requested document couldn't be opened, because there is already a project open. 
The requested document couldn't be opened, because all available windows are In use. 

When you’re running under System 7.0, THINK Pascal displays these errors when it receives an 
AppleEvent it can’t honor. THINK Pascal can’t open a project document if one is already open, and 
it can’t open more than 16 windows. 

This declaration or statement doesn't belong here. 

See Section 8 of Chapter 17. Example: 

unit BadUnit; 
interface 

label { Error: Can't have a label here } 

0 ; 

implementation 

label { Error: Can't have a label here } 

1 ; 

end. 

This doesn't make sense as a statement. 

Everything between a begin and an end must be a statement. See 2.1 and 6 of Chapter 17. 
Example: 

program Nonstatements; 

begin 

{ The following are illegal because they aren't statements. } 

inline 

string; 

aBool * false; { This is an expression, not an assignment } 

const 

unit bad; 

var 

type 

const 

end. 


551 



THINK Pascal User Manual 


This doesn't make sense. 

This error means that THINK Pascal finds something that doesn’t fit the syntax diagrams. See 
Chapter 17. Example: 

program; { Error: missing program name. } 

typa 

StringType = string; 

var 

BadArray : array [5] of char; { Wrong } 

GoodArray : array[1..5] of char; { Right } 


PointerToString : A string; { Wrong: Can't use STRING in } 

{ an anonymous type } 

PointerToString : A StringType; { Right } 

n : Extended; { Wrong: can't use special characters 1 

{ in identifiers } 

Pi : Extended; { Right } 

procedure ProcWithoutArgs; 
begin 

aChar := ' 7C'; {OK: can use these set for strings & comments } 

end; 

begin 

anlnt :«; { Error: missing value } 

ProcWithoutArgs(); { Wrong: Procs and Funcs without } 

{ args mustn't have () } 

ProcWithoutArgs; { Right: It does look funny if you are } 

{ used to the C Language } 

if true then 


writeln('Error: semicolon doesn't belong at end of this line 
else { See 6.2.2.1 of Chapter 17 } 

writeln('OK: the problem is with the previous writeln'); 
writeln('Error: Missing close quote -> ); 

Error: missing open comment } 

{ Error: missing close comment 

end. 

This file Is marked "read-only" by Projector. Choose "Save As..." to make an editable 
copy. 

The Projector-Aware option is on, and you just tried to edit a file that Projector marked read-only. 
To edit the file, you must make a copy of it. Choose Save As... and enter a new file name in the 
standard file dialog. THINK Pascal copies the file’s text, but not its Projector resource. For more 
information on the Projector Aware option, see “Using MPW PRojector with THINK Pascal” in 
Chapter 6, “Editing.” 

This Is not allowed In the Instant window. 

The THINK Pascal Instant window is special. It can execute any Pascal statement that would be le¬ 
gal at the point where your program is currently halted, except for gotos. See Section 6 of Chapter 
17. 

New declarations are not allowed. You might want to declare some scratch variables in your main 
program for use in the Instant window. 


552 



Error Messages 


D 


This statement or keyword doesn't belong here. 

Possible misplaced or missing keywords. See 8.1, 2.1, and 8.3 of Chapter 17. Example: 

program BadProgram; 

writeln('BAD'); { Error: statements don't go in declaration part } 

i : integer; { Error: Need VAR before declaring variables } 

typ® 

t - integer; 

®nd; { Error: END doesn't go after TYPE declaration } 

begin 

and. { End of BadProgram } 

Another example: 

unit BadUnit; 
intarfaca 
label 

13; { Error: labels can't be made visible outside the unit } 

implementation 

label 

13; { Error: labels can't be shared inside the unit } 

procedure empty; 

begin 

end; 

end. { End of BadUnit } 

Too few parameters used in procedure or function call. 

See 7.3 of Chapter 17. 

Too many constants in enumerated type. 

For efficiency, enumerated types are implemented as unsigned byte values ranging from 0 to 255. 
Therefore, an enumerated type can have a maximum of 256 enumerated constants. 

Too many Indices are being applied to a variable or expression. 

Array elements have to be accessed the same way in which they are declared. See 4.3 and 4.3.1 of 
Chapter 17. Example: 

var 

OneDim : array[1..10] of integer; 

TwoDim : array[1..10, 1..10] of integer; 

begin 


OneDimfl][2] 

:- 

3; 

{ Error } 

OneDimfl, 2, 

3, 

4 ] : - 4 ; 

{ Error } 

OneDim [3] :- 

5; 


{ OK } 

TwoDim[1][2] 

: - 

3; 

{ OK } 

TwoDim[1, 2] 

: = 

4; 

{ OK: Pascal allows either form } 


end; 


553 



THINK Pascal User Manual 


Too many NEAR-placed modules. 

You’re compiling a project with the “Far Code” option on, and it contains too many libraries 
compiled with the “Far Code” option off. Try recompiling the libraries with the “Far Code” option 
on, or put all the libraries with the “Far Code” option off togeher in their own segment. For more 
information on the “Far Code” option, see “Building applications with large jump tables” in Chapter 
12, “Building Projects.” 

Too many nested {$IFC} or {$PUSH} directives 

You can nest { $IFC} directives only 16 levels deep and { $PUSH} directives only 8 levels deep. 

procedure test; 
begin 

{$IFC TRUE} 

($IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

($IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

($IFC TRUE} 

{$IFC TRUE} 

($IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} 

{$IFC TRUE} { ERROR: limit of 16 nested $IFC directives } 
writeln; 

end; 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} 

{$PUSH} { ERROR: limit of 8 nested $PUSH directives } 

{$R~} 

procedure NullifyString (s: string); 


Too many parameters used in procedure or function call. 

See 7.3 of Chapter 17. 


554 



Error Messages D 


Too many up-arrows ( A ) are being applied to a variable or expression. 

Too many up arrows result in too many dereferences. See 4.3 and 4.3.4 of Chapter 17. 

typ« 

pType - A integer; 

PPType « A pType; 

var 

p : pType; 

PP : PPType; 
i : integer; 

begin 


anlnt 

:- p AA ; 

{ Wrong 

} 

anlnt 

:« P A ; 

{ Right 

} 

anlnt 

:- PP AAA ; 

{ Wrong 

} 

anlnt 

PP AA ; 

{ Right 

} 


end; 

Type expected. “ symbol ” Isn't a type. 

See sections 3 and 4 of Chapter 17. Example: 

var 

NotAType : integer; 

s : set of NotAType; { Error: NotAType is not a type } 

i : NotAType; { Error: NotAType is not a type } 

BadArray : array [aConstant] of char; { Wrong: needs a type } 

{ or subrange } 

GoodArray : array [1..aConstant] of char; { Right } 

type 

aBadType “ NotAType; { Wrong } 
aGoodType * integer; { Right } 

begin 

end; 

Type Incompatibility between an actual and formal procedural or functional parameter. 

The functional or procedural parameter list must match the parameter list declared in the called 
subroutine. See 7.3.5 of Chapter 17.Example: 

procedure PI (r : real); 

begin 

end; 

procedure P2 (x, y : integer); 

begin 

end; 

procedure CalIP (procedure aProc (i : integer)); 
begin 

aProc(4) ; 

end; 

function F (i : integer) : real; 

begin 

end; 


555 



THINK Pascal User Manual 


procedure CallF (function aFunc (i : integer) : integer); 

begin 

writeln(aFunc (4) ); 

end; 

begin 

CallP(Pl); { Error: PI doesn't have same parameter types as aProc } 

CallP(P2); { Error: P2 doesn't have same number of args as aProc } 

CallF(F); { Error: F doesn't have same result type as aFunc } 

end; 

Type Incompatibility between an actual and formal value parameter. 

Pascal requires assignment compatibility between actual value parameters (the actual expressions 
passed to a subroutine) and formal value parameters (the arguments in the subroutine definition). 
Assignment compatibility of types can be subtle. See 7.3.1 and 3.5.3 of Chapter 17. Example: 

typo 

Canonical = array[1..4] of char; 

Indentical = Canonical; 

AnotherType = array[1..4] of char; 

var 

AnonArray : array[1..4] of char; 

CanonicalArray : Canonical; 

IdenticalArray : Indentical; 

AnotherArray : AnotherType; { a 
PAC : packed array[1..6] of char; 
procedure RealValue (r : real); 
begin 
end; 

procedure IntValue (i : integer); 

begin 
end; 

procedure ArrayValue (a : Canonical ); 

begin 
end; 


begin 

RealValue(aReal); { OK } 

RealValue(anExt); { OK: anExt gets converted to real } 

RealValue(anlnt); { OK: anlnt gets converted to real } 

RealValue(aLong); { OK: aLong gets converted to real } 

IntValue(aLong); { OK: aLong gets converted to integer } 

IntValue(aColor); { Error: enums don't get converted to integer } 

IntValue (aReal); { Wrong: reals don't get converted to integer } 

IntValue(round(aReal)); { Right } 

IntValue(aPtr); { Error } 

anlnt :- length('string'); { OK } 

anlnt :- length(aChar); { OK: aChar is treated as a string } 

anlnt :- length(PAC); { OK: PAC [1..N] is treated as a string } 

anlnt :- length(AnonArray); { Error: unpacked arrays don't } 

{ get converted } 


{ a type } 

{ an identical type with Canonical } 

{ type different from Canonical } 

{ an array of an anonymous type } 

{ a variable of a named type } 

{ a variable of a same named type } 

variable of a different named type } 


{ type of a must be named } 


556 



Error Messages D 


{ These examples are subtle 
ArrayValue(CanonicalArray); 

ArrayValue(IdenticalArray); 

ArrayValue(AnonArray); 

ArrayValue(AnotherArray); 

end; 

Do not redeclare a type that is in one of the built-in intefaces. If you redeclare one of those types 
and try to call a Toolbox routine that requires an argument of that type, you get this error. Example: 

program test; 
type 

rect = record 

top, left, bottom, right: integer 

end; 

var 

r: rect; 

begin 

SetRect(r, 10, 5, 200, 100); 

end. 

Type Incompatibility between an actual and formal VAR parameter. 

Pascal requires the types of actual var parameters (the variable passed to a subroutine) and the 
types of formal var parameters (the arguments in the subroutine definition) to be identical When 
a parameter is passed to a formal var parameter, the called subroutine can change the actual pa¬ 
rameter passed, not just a copy of it. Therefore, the data representation of the actual parameter 
must exactly match the data representation of the formal parameter. Type identity can be subtle. 

See 7.3 2 and 3-5.1 of Chapter 17. 

typ® 

Canonical = array [1.. 4] of char; { a type } 

Indentical - Canonical; { an identical type with Canonical } 

SomeType - array[1..4] of char; { type DIFFERENT from Canonical } 

var 

AnonArray : array [1.. 4] of char; { an array of an anonymous type } 

CanonicalArray : Canonical; { a variable of a named type } 

IdenticalArray : Indentical; { a variable of a same named type } 

SomeArray : SomeType; { a variable of a different named type } 

PAC : packed array[1..6] of char; 


- see 3.5.1 of Chapter 17 } 

{ OK } 

{ OK: the types are identical } 

{ Error: anonymous types aren't } 

{ identical with anything } 

{ Error: the named types are different } 


557 



THINK Pascal User Manual 


procedure RealVar (var r : real) ; 

begin 

end; 

procedure IntVar (var i : integer); 

begin 

end; 

procedure StringVar (var s : string); 

begin 

end; 

procedure ArrayVar (var a : Canonical ) ; { type of a must be named } 

begin 

end; 

begin 

RealVar(aReal); { OK } 

RealVar(anExt); { Error: types must match exactly for VAR } 

RealVar(anlnt); { Error } 

RealVar(aLong); { Error } 

IntVar(anlnt); { OK } 

IntVar(aColor); { Error } 

IntVar(aLong); { Error } 

IntVar(aReal); { Error } 

IntVar(aString); { Error } 

IntVar(aPtr); { Error } 

StringVar(aString); { OK } 


StringVar(aString25); { OK: any string type is identical to } 

{ type VAR s:STRING } 

StringVar(aChar); { Error } 

StringVar(PAC); { Error } 

StringVar(AnonArray); { Error: unpacked char arrays } 

{ don't match strings } 

{ These examples are subtle - see 3.5.1 of Chapter 17 } 

ArrayVar(CanonicalArray); { OK } 

ArrayVar (IdenticalArray) ; { OK: the types are identical } 

ArrayVar(AnonArray) ; { Error: anonymous types aren't } 

{ identical with anything } 

ArrayVar(AnotherArray); { Error: the named types are different } 

«nd; 


Type Incompatibility. 

You can’t add apples and oranges. Pascal catches illogical statements that try to use incompatible 
types. On occasion, this rule needs to be broken. The following examples show common errors 
and methods to break the rules. Use the methods at your own risk. Type compatibility can be 
subtle. See 3 5.2 and 5 of Chapter 17. Example: 

var 

PtrToInt : A integer; 

PtrToChar : A char; 

begin 

aBool :- (aColor = 1); 
aBool (Ord(aColor) = 1); 


{ Wrong: can't compare } 
{ incompatible types } 
{ Right: but what do you } 
{ really want to do? } 


558 



Error Messages D 


aBool : 

aBool : 
aBool : 

aBool : 

aBool : 
aBool : 

aBool : 
aBool : 

aBool : 

aBool : 

aBool : 

and; 

Type or procedure name used where a variable, field name, or value Is required. 

See Sections 5 and 6 of Chapter 17. Example: 

type 

aType = integer; 
aName = integer; 

var 

aRecord : record 

aName : integer 

and; 

procedure aProc; 
begin 
end; 
begin 

anlnt := aName; { Error: aName refers to a type in this statement} 

if anlnt = aType then { Error: aType is not a value } 

9 

with aRecord do 

begin 

anlnt := aName; { OK: aName refers to field in } 

{ aRecord in this statement } 

anlnt := aProc; { Error: aProcedure is not a value } 

anlnt := aType; { Error: aType is not a value } 

end; 

end; 


= (aColor = ColorType (1) ) ; { Also Right: but what do you } 

{ really want to do? } 

= (aString = aChar) ; { OK to compare strings to char } 

= (aString = anlnt); { Wrong: strings and integers } 

{ aren't compatible } 

= (aString = stringof(anlnt : 1)); { Right: anlnt is converted} 

{ to a string } 

= (red in [red..violet]); { Right } 

- (2 in [red..violet]) ; { Wrong: 2 isn't in } 

{ set of ColorType } 

= (red in [red..violet]); { Right } 

= ('a' in [$OD..'z']); { Wrong: $0D is a different } 

{ type from 'z' } 

« ('a' in [chr($0D)..'z']); { Right: chr($OD) is } 

{ a carriage return } 

= (PtrToInt = PtrToChar); { Wrong: pointers are of } 

{ different types } 


= (pointer (PtrToInt) = PtrToChar); { Right: but what do you } 

{ really want to do?} 


559 



THINK Pascal User Manual 


Unexpected end of file. 

EOF (End Of File) was reached while doing a Read. You should always check for EOF before 
reading. See 9.9 of Chapter 17. Example: 

RESET(FileOfText, 'input file'); 

while true do { Error: eventually tries to read past end of file} 

readln(FileOfText, aString); 
close(FileOfText); 

RESET(FileOfText, 'input file•); 

while not eof (FileOfText) do { Right: checks for EOF } 
readln(FileOfText, aString); 

USES only allowed Immediately after PROGRAM heading , INTERFACE, or 
IMPLEMENTATION. 

See 8.1 and 8.3 of Chapter 17. Example: 

program WhichUsesUnits; 

uses 

aUnit; { Right } 

var 

i : integer; 

uses 

AnotherUnit; { Wrong } 

begin 

end. 

Variable or function name expected. “ symbol ” Isn't a variable or function. 

The target of an assignment must be a variable ora function name when a return result is being set. 
See 6.1.1 and 7.2 of Chapter 17. 

type 

NotAVariable - integer; 

var 

aVariable : integer; 
aPtrToInteger : A integer; 
procedure aProcedure; 
begin 
end; 


function aFunction : 
begin 

NotAVariable :« 
aVariable := 4; 
aPtrToInteger A : 
aProcedure 4; 
aFunction := 4; 

end; 


integer; 

4; { Wrong: NotAVariable is not a variable 

{ Right } 

*4; {Also Right } 

{ Wrong: aProcedure is not a function name 
{ Right: this is how functions return values 


} 

} 

} 


560 


Variables of a file type or a type which contains a file type can't be assigned. 

For every open File, there must only be one copy of the File-variable. The operating system needs 
file-variables for File input/output. If a copy of the File-variable could be made, and both were used 



Error Messages 


D 


for file I/O, then the file would be inconsistent. Therefore, making a new copy of a file-variable is 
forbidden. Example: 

var 

file_l, file_2 : file of integer; 

array_l, array_2 : array[1..3] of file of integer; 
record_l, record_2 : record 
FileName : string; 

FileParameter : file of real; 
end; 

begin 

open(file_l, 'My file'); 

file_l file_2; { Error: could cause havoc with filesystem } 

close(file_2); { especially, if you did this } 

array_l := array_2; { Error: these arrays contain filetypes } 

record_l := record_2; { Error: these records contain filetypes } 

end; 

Variables of this type would be too large. 

Because THINK Pascal use 1 6 bit offsets (the MC68000 architecture doesn’t allow 32 bit offsets), a 
data structure cannot exceed 32766 bytes. 

type 

rec « record 

ar : packed array [0..40000] of char; 
sp : integer; 

end; 

Variant-part of record contains no variants. 

See 3.2.2 of Chapter 17. Example: 

type 

BadVariantRecordType = record 
case tag : integer of 

{ Error: must have at least one variant here } 

end; 

When using FAR CODE, the “%_MethTables” virtual segment must be In a physical 
segment by Itself. 

When the “Far Code” option is on, the entry %_MethTables must be in a segment by itself. For 
more information, see “Segmenting a Project” in Chapter 7, “Working with Projects.” 

While your program Is halted, you may not manipulate your program's windows. 

While your program is halted, your code, which handle events in your program’s windows, is not 
running, so you can’t manipulate your program’s windows. 

Writing over a project or library Is not allowed. 

This is a safety feature that prevents you from overwriting a project or library by accident. You can 
delete the project or library with the Delete command in the File menu. 


561 



THINK Pascal User Manual 


You already have a window named “Namel”. Would you like to open your file as 
“Untitled N”? 

You may have tried to open a file twice. You may have two different files with the same name but 
in different volumes or folders. At this point, you can either open the file and see what's in it, or 
you can cancel. 


program InputAndOutput(input, output) 

begin 

reset(output); { Wrong ) 

reset(input); { Right ) 

rewrite(input); { Wrong } 

rewrite(output); { Right ) 

end. 


You can’t CLOSE an anonymous file. 

Unnamed files are sometime also referred to as anonymous files. See 9.1 and 9.2.4 of Chapter 17. 
Example: 


var 

f : Text; 

begin 

rewrite(f); { Associate an unnamed file with f } 

close (f); { Wrong: can't close an unnamed file } 

end; { When the scope the file variable is exited, f will be closed } 

{$ELSEC} or {$ENDC} (or {$POP» has no matching ($IFC) (or {$PUSH}) 

Every {$ELSEC} or { $ENDC} must have a matching { $IFC}, and every {$POP} must have a 
matching {$PUSH}. 

procedure test; 
begin 

{$SETC compiler_var * false) 

{$IFC compiler_var} 

writeln('This line will not be compiled'); 

{$ELSEC) 

writeln('This line will be compiled'); 

{$ENDC) 

{$ELSEC) { ERROR } 

{ $ENDC) { ERROR } 

end; 

{$PUSH) 

{$R-} 

procedure NullifyLength (s: string); 
begin 
s[0]:«0; 
end; 

{$POP} 

{$POP} { ERROR } 


562 



Index 


Entries in bold face refer to menu commands. Entries in typewriter face refer to functions, 
methods, variables, keywords, or files. 


Symbols 


#, Pascal Source Converter 397 
$, Pascal Source Converter 397 
* 292, 294 
** 486 
+ 292, 294 
- 292, 294 
/ 292 
<295 
<= 295 
<> 295 
= 295 
>295 
>= 295 

?, Pascal Source Converter 397 

@ operator 279, 296 

>450 

>>450 


A5 world 175 

About THINK Pascal... 223 
ABPackage. lib 144 
abs 357 

absolute value 357 
accessing resource data 426 
activations 264, 265-266 
ADBS resource 164 
Add Jlle 237 

Add Current Directory button 
SADeRez 457 

Add File... 101, 136, 184, 237 
Add Window 101 
addition 292 

aerosol can icon (see bug spray can icon) 
align types, in resource descriptions 417 
All Text Files option 443 
SADeRez 456 
alternate input file 
SARez 449 
and 293 

anonymous file 332 
ANS Pascal 475-479 
APDA 11 


apostrophe, in a string 260 
appheap attribute 411 
Apple Computer 11 

Apple Numerics Manual, Second Edition 271 
Apple Programmer’s and Developer’s Association 11 
AppleTalk 144 
AppleTalk.p 144 
application 

building 150-151, 171 
globals 175, 176 
heap 174 
parameters 175 
arccos 218 
arcsin 218 
arctan 218, 359 
arctanh 218 
arguments 

on stack 181 
arithmetic functions 356 
arithmetic operations 

checking for overflow 209 
arithmetic operators 268, 292 
Arrange... 77, 252 
arranging windows 77 
array data, in resource descriptions 423 
array type, in resource descriptions 418 
array-type 273 
$$ArrayIndex () 427 
arrays 273, 284 

checking index bounds 210 
examining in LightsBug 192 
over 32K 484 

over 32K elements, in LightsBug 193 
referring to elements 285 
representation 178 
arrow keys 81 

assembly code .examining 129 
assembly language 139, 173-184 
assignment 

checking bounds 210 
assignment compatibility 281 
assignment statements 302 
$$Attributes 411, 437 
attributes 

in SARez 411 


563 



THINK Pascal User Manual 


Auto-Ref ormat 79, 232 
Auto-Reopen 77, 253 
Auto-Save 117, 248 
Auto-Show Finger 123, 251 
automatic execution commands 127 

B 

backing up files 386 
BAND 366 
base-type 276, 279 
BCLR 367 

Beekman, George 9 
$BEEP 400 

BEGIN starts a new line option 91 
binary operations 287 
BlnlineF 373 
bit operations 365-368 
Bit And 365 

$$BitField() 426,437 
BitNot 365 
BitOr 365 

bitstring type, in resource descriptions 415 
BitXor 365 
blocks 262 

activation 265 
BNDL resource 148 
BNOT 366 
boolean 268 

definition 268 
operators 293 
representation 177 
short circuit 492 

Boolean types, in resource descriptions 415 
BOR 366 

bounds checking (see Range compiler directive) 
%_BP 208 

Break at A-Traps 201, 251 
breakpoints (see Stop Signs) 

BROTL 367 
BROTR 367 
Browser 253 
BSET 368 
BSL 366 
BSR 367 
BTST 367 
bug icon 114 

bug spray can icon 115, 122 
Build 117, 246 

Build Application... 171, 238 
Build Code Resource... 171, 238 
Build Desk Accessory... 171, 238 
Build Driver... 171, 238 
Build Library... 137, 238 
build order 102 


building programs 117 

built-in functions, resource descriptions 426, 436 

Bundle bit 148 

BXOR366 

byte type, in resource descriptions 415 

c 

callback routines,in code resources 170 
callback routines,in drivers 156 
calling conventions 180-182 
calling sequence 180 
can, bug spray (see bug spray can icon) 
case label subranges 491 
case statements 308 
case-constants 308 

cash register icon (see LightsBug, register display) 

CDEF resource 164 

cdev resource 164 

change statement 422 

changed attribute 412 

char 269 

definition 269 
representation 177 
subrange 270 
character string 260 

character types, in resource descriptions 415 

character-pairs 258 

chars 

comparing 295 
Check link 115, 117, 246 
Check Syntax 117, 246 
Chernicoff, Stephen 11 
choosing types to decompile 459 
chr 359 

CKID resource 93 
Clancy, Michael 9 
Class Browser 253 
classes 277-278 
in libraries 139 
public 139 
Clear 229 
clicking 

Command-dick in close box 77 
Command-click in title bar 82 
Command-click on compiler option 109 
Command-Option-click in title bar 82 
Option-click in close box 87 
Option-click in project window 102 
Option-click in title bar 76 
Option-click on compiler option 109 
Option-click on definition 82 
triple-click on line 81 


564 




Index 


Close 87, 224, 335 
SADeRez 462 
SARez 452 

Close All 86, 87, 224 
close box 87 

Command-clicking 77 
Option-clicking 87 
Close Project 100, 236 
closing 

files 87 
projects 100 
cmnu resource 463 
code resources 

building 163, 171 
global data in 166 
headers 165, 168 
ID number 165 
locking 167 
main function 165 
multi-segment 168 
naming 165 
reentrant 167 
setting attributes 165 
setting the project type 164 
type field 165 

using callback routines 170 
using trap intercept routines 170 
writing 165 

coercion (see type casting) 
collected views 187, 194 
collections (see LightsBug, collected views) 
Command Line box 442 
SADeRez 454 
Command-clicking 
in close box 77 
in title bar 82 
on compiler options 109 
Command-Option-clicking 
in title bar 82 

Command-Shift-Period 115, 122 
comments 262 
nested 399 
Compare, MPW 400 
compatibility 

assignment 281 
type 281 

compatibility with earlier versions 467 
compdate 375 

compilation, changing order of files 102 
compilation time routines 375 
Compile Options... 215, 242 
compile-time variables 214 
compiled code, examining 129 
compiler directives 203-219, 243 


$ELSEC 214 

$ENDC 214 

$IFC 214 

$SETC 214 

Debug 207 

External Routine 213 

External Variable 212 

Initialization 211 

MPW Pascal 399, 400-404 

Names 207 

Overflow 209 

page break 214 

Pascal Source Converter 400-404 

placing 206 

Pop 213 

Push 213 

Range 210 

segmentation 105, 213 
Tracing 208 

compiler options 108, 203, 262 
Command-clicking 109 
Option-clicking 109 
setting for all files 109 
compiler variables 216 
compiling programs 117 
component-type 273, 277 
compound statements 306 
comptime 375 
CompuServe 12 
computational 271 
representation 177 
concat 361 

conditional compilation 214 

Pascal Source Converter 397 
conditional statements 306-309 
Confirm Saves 117, 248 
conjunction 293 
constant declarations 26l 
constant expressions 490 
constant-declaration-part 263 
control entry, in drivers 154 
control procedures 368 
control-variable 311 
conversion routines 355-356 
from strings 371 
integer to char 359 
integer to pointer 356 
ordinal or pointer t o longint 356, 359 
real to longint 355 
to strings 370 

Converter, Pascal Source 395, (see also Pascal Source 
Converter) 

Cooper, Doug 9 
Copy 228, 361 


565 



THINK Pascal User Manual 


cos 218, 358 
cosh 219 
$$countof () 418 
creating files 75 
creating projects 98 
$CREATOR400 
creator 148 

cstring type, in resource descriptions 4l6 
Cut 228 

Cycle 369, 490 

D 

$D 207 

DA Shell 162 
data statement 412 
data type representation 176 
data types 176 

data, in resource descriptions 423 
array 423 
switch 423 

data-type, in resource description (see types) 
$$Date 436 
$$Day 437 

Debug compiler directive 207 
Debug option 123 
Debugger 375 
DebugStr 375 
declaration-part 262 
declarations 

constants 26l 
functions 318 
methods 327 
procedures 315 
scope 264 
variables 283 
Decompile box 459 
defining-declaration 316 
definitions,finding 82, 190 
delete 362 
delete statement 421 
Delete... 227 
$DEPEND 401 
Description Files... button 
SARez 443 

desk accessories (see also device drivers) 151-163 
debugging 162 

device drivers (see also desk accessories) 151-163 
building 151-163, 171 
closing 159, 160 
control entry 154 
dCtlDelay 158, 159 
dCtlEMask 158, 159 
dCtlFlags 158, 159 
dCtlMenu 158, 159 


drvrEMask 158, 158 
drvrFlags 158, 158 
event mask 158 
event record 155 
flags 158 

global data in 155 
headers in 157 
how they work 153 
I/O parameter block 154 
jlODone 160-161 
libraries, imported 157, 167, 183 
main function 154 
multisegment 153, l6l 
naming 152, 153 
opening 159 
preloading segments l6l 
returning from 159, 160 
segmentation 163 
setting project type 152, 153 
unloading segments 162 
using callback routines 156 
using Object Pascal 153 
using QuickDraw globals 157, 166 
using trap intercept routines 156 
writing 154 
Device Manager 153 
devices 351-352 
difference 294 
.diff files 400 
$DIFFS401 
$DIR 401 
directive entry 107 
directives 259 

directives,compiler (see compiler directives) 

disjunction 293 

dispose 354 

dLiv 292, 293 

division 293 

Don’t escape characters option 459 
Don’t Find button 84 
Don’t Save 117, 248 
double 271 
range 271 
representation 177 

drawer icon (see LightsBug, collected views) 
Drawing 254 
Drawing window 

routines 363-365, 370 
using in applications 150 
drivers (see desk accessories and device drivers) 
DRVRRuntime. lib 141, 153, 156 
DumpProf ile 393 
DumpProfileToFile 393 
dynamic allocation routines 353, 355 


566 



Index 


dynamic-variables 279, 287 

E 

Echo to file 119 
Echo to printer 119 
editing files 78-83 

editing values, in LightsBug 188, 195 
Elems881 216, 217 
else 307 
$ELSEC 214, 401 
empty set 277 
End key 82 
$ENDC 214, 401 
Enter Selection 84, 235 
Entire Document 88 
enumerated types 269 
comparing 295 
representation 177 
subrange 270 
eof 336 
eoln 347 
%_EP 208 
equal to 295 
error file 

SADeRez 457 
SARez 449, 452 
error messages 493 
errors 

input/output 352 
moving to 81 
SADeREZ 46l 
SAREZ 451 
syntax 79 

escape characters, resource descriptions 439 

event mask, drivers 158 

event record, in drivers 155 

%_EX 208 

examples 

labels in SARez 429 

sample resource description file 409, 423 
sample resource type statement 420 
execution commands 127 
execution finger 116 , 122, 123 
with "A” 201 

execution position (see execution finger) 

Exit 369, 490 

exp 219, 358 

expl 219 

exp10 219 

exp2 219 

expanded view 187, 192 
exponentiation 486 

exporting routines, types, variables 132 


expressions 287-301 
constant 490 
in constants 26l 
simple 290 
syntax 291 

expressions, in resource descriptions 435 
extended 271 
range 271 
representation 177 
external 139 
external declarations 317 
External Routine compiler directive 213 
External Variable compiler directive 212 
eye on folder icon (see LightsBug, watchpoints) 

F 

factor 289 

fake nose and glasses icon (see LightsBug, type cast 
value 

Far Code option 180 
fields 274, 286 

file cabinet icon (see LightsBug, collected views) 

file entry 104, 107 

File To Decompile button 455 

file type 148 

File Windows 254 

file-buffer 286, 333 

file-type 277 

file-variable 286 

f ilepos 337 

files (see also units), 277, 332 
accessing randomly 333 
accessing sequentially 333 
adding to projects 101 
anonymous 332 
backing up 88, 386 
buffer 333 

changing compilation order 102 

closing 87 

components 333 

creating 75, 332 

creating function 372 

declaration 277 

editing 78-83 

file-type 277 

file-variable 286 

moving in 81, 82 

moving in projects 102 

moving in segments 104 

non-textfile routines 337-339 

opening 75, 76, 77, 332 

opening function 371 

options, SADeRez 460 

options, SARez 450 


567 



THINK Pascal User Manual 


organizing 96 
position 333 
printing several 86, 384 
referring to components 286 
removing from projects 102 
replacing files in projects 102 
representation 179 
routines for all 333-337 
saving 87, 117 
saving with new name 87 
text file routines 339, 331 
without external file 332 
files,standard type declaration 407 
fill types, in resource descriptions 417 
Find Again 83, 85, 234 
Find button 84 
Find in All Files 86 
Find in Next File 86, 234 
find options 84 

setting up for later 84 
finding definitions 82 
LightsBug 190 
finding selection 81 
Find... 83, 233 

finger icon (see execution finger) 
fixed-part 274 
FKEY resource 164 

folder with eye icon (see LightsBug, watchpoints) 
Folsom, Rachel 9 
font,changing 89 
for statements 311 
exiting 368 

formal parameter list 320 
compatibility 325 
$$Format() 436 
formatting (see pretty-printing) 
forward declarations 316 
FPU 

initializing 212 
using 217-219 
free memory 174 
function-declaration 318 
function-heading 319 
functional parameters 321, 325 
functions 315 

address of 298 
arithmetic 356 
as l-values 299 
calling 174, 298-300 
calling conventions 180-182 
calling sequence 180 
declarations 318 
entry 180 

examining in LightsBug 188 


exit 181 
external 139 

external declarations 317 
forward declarations 316 
in libraries 137 
inline declarations 318 
ordinal 359 
parameters 320 
passing parameters 182 
public 137 
recursive 265 
results, generalized 491 
return values 182 
scope 264 
stack, on entry 181 
standard 141, 353-375 
stepping into 124 
stepping over 124 
timing (see profiler) 

Toolbox (see Toolbox) 
using @ 298 
using as l-values 491 
using in other units 132 

G 

Generic 374 
get 336 
Get Info... 109 
GetDrawingRect 364 
GetTextRect 364 
global data 

amount in project 109 
application 175, 176 
desk accessories 155 
device drivers 155 
in code resrouces 166 
QuickDraw 175 

QuickDraw, in drivers 157, 166 
glue code 142 
Go 113, 127, 247 
Go-Go 124, 127, 247 
goto statements 303 
greater than 295 
greater than or equal to 295 

Groucho Marx icon (see LightsBug, type cast value) 

H 

Halt 369, 490 

hand icon (see execution finger) 
handles 

checking for nil handle 210 
dereferencing in LightsBug 192, 199 


568 




Index 


headers 

code resources 168 
in code resources 165 
in drivers 157 
heap 174 
heap display 187 

heap icon (see LightsBug, heap display) 
heap size 119 
heap zones 

examining in LightsBug 197 
HeapCheck 355 
HeapResult 355 
Help box 442 
SADeRez 454 
hexadecimal numbers 259 
Hide All 363 
hiding project window 100 
hiding windows 77 
HiWord 368 
HiWrd 368 
Home key 82 
host-type 270 
$$Hour437 

How to Write Macintosh Software 11 

I 

$1 211, 398 

I/O parameter block, in drivers 154 
icons 

LightsBug 187 
$ $ ID 411, 437 
identical types 280 
identifiers 258 
scope 264 
identity 293 
IEEE 218 

if statements 307 

if-then-else directives 432 

$IFC 214, 397, 401 

implementation 132 

Implementation uses 135 

implicit parameters 326 

importing routines, types, variables 132 

in 295 

include 363 

include file directive 398 

Include Paths... button 447 

$INCLUDES 402 

include statement 410 

Indent BEGIN/END within statements option 91 
Indent statements within BEGIN/END option 92 
indentation,changing 91 
index-type 273 
indices 284 


INIT resource 164 
InitFPState 212 
initialization, automatic 211 
Initialization compiler directive 211 
InitProfiler 393 
inline declaration 318 
InlineP 373 
$ INPUT 396,402 
input parameter 328, 333 
input/output 331 

error handling 352 
lazy 348,351 
modem 351-352 
printer 351-352 
insert 363 
insertion point 

moving 81, 82 
moving to 81 
Inside Macintosh 10 
Instant 251 

Instant Project option 99 
Instant window 122, 129 
saving 129 

integer type, in resource descriptions 415 
integers 268 

comparing 295 
converting 356, 359 
range 268 
representation 176 
subrange 270 
syntax 259 

interactive I/O 348, 351 
interface 132 
interface file 136, 137 
Interface. lib 98, 142 
internationalization of resources 421 
intersection 294 
IOCheck352 
IOResult352 

J 

$J 212 

Jensen, Kathleen 9 
j IODone, in drivers 160 
Johnson, Michael 9 
jump table 175, 176 

K 

keywords 

appearance in files 90 
Knaster, Scott 11 
Kronick, Scott 9 


569 



THINK Pascal User Manual 


L 

1-values 

function calls 299 
function results as 491 
type casting 492 
label-declaration-part 263 
labels 

declaring 263 
scope 264 
syntax 260 

labels, in resource descriptions 423 
declaring in arrays 427 
examples 429 
limitations 427 
Large sets option 219 
lazy I/O 348,331 
LDEF resource 164 
Leave 369, 490 

Leave behind “CMNU” resources 464 
length 360 

of strings 278 
less than 295 
less than or equal to 295 
libraries 136 

adding to projects 101 
imported 182 

imported, in desk accessories 183 
imported, in device drivers 183 
imported, in drivers 157, 167 
in drivers 157, 166 
interface files 137 
standard 141, 353-375 
using 136 
writing 137 
LightsBug 185, 250 

collected views 187, 194 

dereferencing handles and pointers 192, 199 

edit values 188,195 

editing memory 200 

examining arrays 192 

examining many variables 194 

examining objects 192 

examining records 192 

examining sets 192 

examining subroutines 188 

examining variables 191 

expanded view 187,192 

finding subroutine definitions 190 

heap display 187, 197 

icons 187 

memory display 198 
opening several 186 
panes 186 


register display 187, 196 
scope 191 

subroutine call chain 188 
Toolbox routines 201 
trash 188 

type casting 188, 195 
variable display 187, 191 
watchpoints 187, 194 
$LINE 402 
lines 

selecting 81 

Link Errors window 115 
linking programs 115, 117 
LInlineF 373 

literals, in resource descriptions 434 
In 219, 358 
lnl 219 

locked attribute 412 
locking code resources 167 
loglO 219 
log2 219 

$$Long() 426,437 
Long names option 208, 219 
longint 268 
range 268 
representation 176 

longint type, in resource descriptions 415 
LoWord 368 
LoWrd368 

M 

MacApp 

memory requirements 5 
MacApp debugger 208 
MACDEV 12 

machine code,examining 129 
Macintosh Pascal 9 

Macintosh Pascal Illustrated: The Fear and Loathing 
Guide 9 

Macintosh Pascal Programming Primer 11 
Macintosh Programmer’s Workshop 102,184, 238 
Macintosh Programming Secrets 11 
Macintosh Revealed 11 
Macintosh Toolbox (see Toolbox) 
macro variables 
SADeRez 460 
SARez 448 
Macsbug 129, 375 
MacTutor 11 

magnifying glass icon (see LightsBug, expanded view) 
main function 

code resources 165 
desk accessories 154 
device drivers 154 


570 



Index 


Main segment 106 

Make Resource File Read-only option 445 
Mark, Dave 11 

Marx, Groucho icon (see LightsBug, type casting) 
Match Case option 84 
maximum file size 80 
maxint 268 
maxlongint 268 
MBDF resource 164 
MC68020 and MC68030, using 217 
MC68881 and MC68882 
initializing 212 
using 217-219 
MDEF resource 164, 167 
Member 375 
memory 

editing 200 

examining, in LightsBug 198 
memory allocation routines 353-355 
memory options 119 
memory requirements 5 
memory, in applications 174-175, 176 
MENU resource 463 

Merge Resources into Resource File option 445 
message window 
SADeRez 46l 
SARez 451 

method-designator 303 
methods 277 

declarations 327 
«%_MethTables» 108 
$$Minute 437 
mntb resource 463 
mod 292, 293 
modem 351 

Modification date option 446 
Moll, Robert 9 
Monitor 252 
$$Month 437 
moving to error 81 
moving to selection 81 
MPW 102, 184, 238 

porting from (see also Pascal Source Converter), 
481 

MPW .o files, using 492 
MPW Projector 93 
multi-file search 85, 234 
MultiFinder 

running under 119 
multiplication 292 
music playing routine 372 

N 

$N 207 


$N++ 208 
$$Name 411, 436 
Names compiler directive 207 
nAppleTalk.lib 144 
negation 293 
nested use* 135 
New 75, 224, 279, 353 
SADeRez 46l 
SARez 451 

New LightsBug 186 
New Project... 98, 236 
NewFileName 372 
nil 280 

No warnings for redeclared types option 459 

non-relocatable memory 174 

nonpreload attribute 412 

nonpurgeable attribute 411 

not 293 

not equal to 295 

Note 372 

$N0USES402 

null-string 279 

numbers 259 

hexadecimal 259 

numbers, in resource descriptions 434 
numeric types, in resource descriptions 414 

o 

Object Pascal 

in desk accessories 153 
in device drivers 153 

Object-Oriented Programming for the Macintosh 10 
object-type 277 
objects 277-278 

examining in LightsBug 192 
routines 375 
scope of fields 265 
Observe 251 

Observe window 122, 127-128 
saving 128 
odd 356 
. o files 102, 238 
using 492 
Oh! Pascal 9 

Oh! THINK’S Lightspeed Pascal 9 

OK to Replace Protected Resources option 445 

OldFileName 371 

omit 362 

Only Files Ending in .r option 443 
SADeRez 456 
open 335 

Open Project... 100, 236 
opening files 75, 76, 77 
opening projects 100 


571 




THINK Pascal User Manual 


opening units 76 
opening windows 77 
Open... 75,128, 129, 224 
SADeRez 46l 
SARez 451 
operands 287 
operators 287, 291-298 
0 296 

arithmetic 268, 292 
boolean 293, 492 
order of evaluation 291 
precedence 288 
set 294 

in resource descriptions 435 
Option-click 

in title bar 76 
Option-clicking 
in close box 87 
in project window 102 
on compiler options 109 
on definition 82 
options 

68020/68030 217 
68881/68882 217 
compiler 108, 215 
compiler variables 216 
large sets 219 
Long names 208, 219 
memory 119 
Profile 219 
run 118 
save 88, 117 
search 84 
source 89 
Text window 119 
uses features 217 

Options column (see compiler options) 
options file 

SADeRez 460 
SARez 450 

options,compiler (see compiler options) 
or 293 
ord 359 
ord4 356 

order of evaluation 291 
ordinal functions 359 
ordinal types 267 
comparuing 295 
converting 356, 359 
ranges 268 
standard 268 
ordinal-types 270 
ordinal ity 267 
organizing files 96 


otherwise 308 

Outdent declarations option 92 

$0UTPUT 396, 403 

output file menu buttons, SADeRez 458 
output file menus, SADeRez 457 
output parameter 328, 333 
Overflow compiler directive 209 
overlays (see segementation) 
override 277 

P 

$P 214 

pack 476, 488 
packed arrays 273 

representation 178 
packed records 
portable 485 
representation 178, 485 
packed-string-type 273 
$$PackedSize () 437 
page 348 
Page Down key 82 
Page Setup... 86, 226 
SADeRez 462 
SARez 452 
Page Up key 82 
panes, LightsBug 186 

paper icon (see LightsBug, variable display) 
parameter lists,changing format 93 
parameter passing 182 
parameters 320 

functional 321, 325 
implicit 326 

procedural 182, 321, 322 
univ 326 
value 182, 321, 322 
var 182 
variable 321, 322 

Pascal on the Macintosh: A Graphical Approach 9 
Pascal Source Converter 395 
#397 
$ 397 

$input 396 
$output 396 
? 397 

comments 399 

compiler directives 399, 400-404 
converting files 397 
prompting 397 
sample script 404 
scripts 395 

setting directory and file names 396 


572 



Index 


setting input and output 396 
using difference) files 400 
using with MPW Compare 400 
Pascal User Manual and Report 9 
Pascal, ANS 473-479 
Paste 228 

pencil icon 93, (see also LightsBug, edit value), 232 
pile of sand icon (see LightsBug, heap display) 
point type, in resource descriptions 417 
pointer types 279 
pointers 279-280, 287, 296, 356 
checking for nil pointer 210 
converting 356, 359 
creating 279 

dereferencing in LightsBug 192, 199 
nil 280 

representation 177 

pointing finger icon (see execution finger) 

$P0P 213 

Pop compiler directive 213 
pop-up menus 

routine names 82 
unit names 76 
$PORTABLE! 403 
porting 481 

from MPW (see Pascal Source Converter) 
pos 361 
ppat resource 

defined in SARez 429 
precedence rules 287-288 
precision 

of real types 271 
pred 360 
predecessor 267 
predefined routines 141 
preload attribute 412 
Preprocessor box, SADeRez 460 
preprocessor directives 431 
variable definitions 432 
Preprocessor... button 448 
pretty-printing 79 
automatic 79 
options 89 
PrimeTime 145 
Print All Files 86, 226 
PrintCalls.lib 145 
printer 351 
printing 86 
all files 86 

several several files 384 
Text and Drawing Windows 118 
Text window 119 
Printing Manager 145 
Printing.p 145 


PrintTraps.p 145 
Print... 86, 226 
SADeRez 462 
SARez 452 

procedural parameters 182, 321, 322 
procedure statment 302 
procedure-and-function-declaration-part 263 
procedures 315 
address of 298 
calling 174 

calling conventions 180-182 
calling sequence 180 
declarations 315 
entry 180 

examining in LightsBug 188 
exit 181 
external 139 

external declarations 317 
forward declarations 316 
in libraries 137 
inline declarations 318 
parameters 320 
passing parameters 182 
predefined 141 
public 137 
recursive 265 
scope 264 
stack, on entry 181 
standard 141, 353-375 
stepping into 124 
stepping over 124 
timing (see profiler) 

Toolbox (see Toolbox) 
using @ 298 

using in other units 132 
profiler 391-393, 394 
option 219 

program parameters 328 
program syntax 327 
programs (see also projects), 327-331 
building 117 
compiling 117 
halting 369 
linking 115, 117 

position in (see execution finger) 
resetting 126 
restarting 126 
running 113-119 
stepping through 124 
stopping 115-116, 122, 124 
tracing 124 

Progress information option 446, 459 
Project name 252 
project tree 96 


573 



THINK Pascal User Manual 


project type 148 
Project Utilities 379 

backing up files 386 
printing files 384 
printing window 382 
reading display 381 
saving file pathnames 382 
selecting files 383 
project window 96-97 
customizing 110 
hiding 100 
option-clicking 102 

Options column (see compiler options), 204 
segment view 104, 107 
Projector Aware option 232, 93 
projects 95-111, (see also programs) 
adding files 101 
arranging files 102 
backing up files 386 
changing compilation order 102 
closing 100 
corrupted 111 
creating 98 
moving files 102 
opening 100 
printing files 384 
removing files 102 
replacing files 102 
saving file pathnames 382 
Propagated uses 135 
protected attribute 412 
protected bit,in resource descriptions 422 
pstring type, in resource descriptions 4l6 
%_PTrace 394 
public 

classes 139 

functions and procedures 137 
types 137 
variables 139 
Pull All Stops 126 
Pull Stops 126, 251 
purgeable attribute 411 
$PUSH 213 

Push compiler directive 213 
put 337 
qualifiers 284 

Q 

QuickDraw 143 

alternative parameter list 144 
globals 175 

globals, in drivers 157, 166 
Quietly Auto-Reset 126 


Quit 227 

SADeRez 454 
SARez 442 

R 

$R 210 
range 

of ordinal types 268 
of real types 271 
Range compiler directive 210 
read 338, 340 
read statement 412 
readln 343 
Readstring 371 
real 271 

range 271 
representation 177 
real numbers 271 
comparing 295 
converting 355 
ranges 271 
syntax 259 

rearranging windows 77 
record types 274 
records 274-276 
declaration 274 
examining in LightsBug 192 
referring to fields 286 
representation 178 
variant 275-276 

rectangle type, in resource descriptions 417 

recursion 265 

redeclared type 459 

Redeclared types OK option 446 

Redirection... button 449 

reference variable 277, 287 

reference-type 277 

references 277 

register display 187 

register icon (see LightsBug, register display) 

register saving 182 

registers 

examining, in LightsBug 196 
relational operators 295 
relocatable memory 174 
RememberA4 156, 169 
Remove 102, 108, 137 
Remove Objects 111, 239 
repeat statements 309 
exiting 368 

repetitive statements 309-313 
Replace 85, 235 
Replace All 85, 235 
Replace and Find Again 85, 235 



Index 


replacing 85 

representation (see types) 

ResEdit 2.1 Reference 11 
reserved words 258 

appearance in files 90 
Reset 116, 126, 247, 334 
ResetProf ile 393 
resetting programs 126 
Resource Alignment box 445 
resource attributes 411 
resource declarations 407 
resource description file 406 
comments 408 
example 423 

preprocessor directives 408 
SADeRez 455, 457 
SARez 443 
structure of 407 
type declarations 408 
resource description statements 409 
special terms 410 
syntax 409 
resource files 118 
making 150 
using 149 
SADeRez 455 

Resource Output File box, SARez 444 
$$Resource() 436 
resource statement 422 
resource types 
defining 408 

resources (see code resources) 
$$ResourceSize 437 
restarting programs 126 
RestoreA4 156, 170 
return values 182 
Revert 81, 226 
rewrite 334 

Rewrite Resource File option 445 
Rez 1.0 compatibility 459 
round 219, 355 

routines (see also functions and procedures ) 
entry 180 

examining in LightsBug 188 
exit 181 
predefined 141 
RSRCRuntime.lib 170 
Run Options... 118, 149, 249 
running programs 113-119 
runtime environment 174-175, 176 
Runtime . lib 52, 98, 141, 218 
jJ.Runtime.lib 141 


s 

$S 105, 213 
SADeRez 406 

choosing types to decompile 459 

Close 462 

error file 457 

errors 46l 

input files 455 

macro variables 460 

message window 46l 

New 46l 

only option 459 

Open... 46l 

options 458 

options file 460 

output files 457 

Page Setup... 462 

Print... 462 

resource description files 455, 457 
resource file 455 
Save 46l, 462 
Save As... 46l, 462 
skip option 459 
Saderez button 454 
SANE 145, 217, 218 
SANE.p 145 
SANELib . lib 145, 218 
SANELib881. lib 145, 218 
SAPostRez 463-464 
SARez 406 

alternate input file 449 

change resource data 422 

Close 452 

data statements 423 

delete a resource 421 

error file 449, 452 

errors 451 

input files 443 

macro variables 448 

message window 451 

New 451 

options 446 

options file 450 

Page Setup... 452 

Print... 452 

resource description files 443 
Save 451, 452 
Save As... 451, 452 
specify actual resource data 422 
symbolic definitions 421 
symbolic names 425 


575 



THINK Pascal User Manual 


Save 87, 225 

SADeRez46l, 462 
SARez 451, 452 
Save a Copy As... 88, 226 
Save All 86, 87, 225 
Save As... 87, 128, 129, 225 
SADeRez 46l, 462 
SARez 451,452 
save options 117 
Save Positions 77, 253 
SaveDrawing 364 
saving 

all files 87, 117 
files 87 

Instant window 129 
Observe window 128 
options 88 

Text and Drawing Windows 118 
Text window 119 
Schmucker, Kurt 10 
scope 264-265 

declarations of identifiers 264 
in LightsBug 191 
of a declaration 264 
of field 265 

of interface identifiers 265 
of standard identifiers 265 
redeclarations 264 
scripts, Pascal Source Converter 395 
search options 84 

setting up for later 84 
searching 83-86 

multi-file 85, 234 
$$Second 438 
seek 337 

Segment Loader 175, 176 
segmentation 103-108 
changing names 105 
choosing how 106 
combining segments 107 
creating segments 104 
desk accessories 163 
directive 105, 213 
editing attributes 105 
in desk accessories 153 
in device drivers 153 
in drivers l6l 

in project window 104, 107 
moving items 107 
moving segments 104 
Object Pascal 108 
options 106 

removing directive entries 108 
size limit 103 


segments 103, (see also segmentation) 
in code resources 168 
unloading 169 
Select All 229 
selecting lines 81 
selection 

moving to 81 
selector 308 
self 326 

«%_SelProcs» 108 
separators 257 
$SETC 214, 404 
set membership 296 
set operators 294 
Set Project Type... 148, 239 
Attributes 165 
code resources 164 
Custom Header 165 
desk accessories 152 
device drivers 152 
Flag and Mask menus 158 
set-constructors 300 
set-type 276 
SetDrawingRect 364 
sets 276-277 

comparing 296 
declaration 276 
examining in LightsBug 192 
making 300 
representation 179 
SetTextRect 364 

setting protected bit on code resources 422 

SetUpA4 156,169,170 

$$Shell() 436 

short circuit booleans 492 

Show “.Rsrc” files only 464 

Show Clipboard 229 

Show Error 81, 235 

Show Finger 123, 251 

Show Selection 81, 235 

ShowDrawing 364 

ShowText 363 

sign-negation 293 

simple expression 290 

simple statements 302 

simple types 267 

sin 219, 358 

sinh 219 

68020/68030 option 181 
68881/68882 option 217 



Index 


size 

maximum file 80 
of strings 278 
program heap 119 
program stack 119 
program zone 119 
sizeof 369 
$SKIP 404 
Skip box 460 
smart linking 171 
Source Converter, Pascal 
Source Options... 79, 89, 229 
Special-symbols 257 
SPLAsh 12 

spray can icon (see bug spray can icon) 

sqr 357 

sqrt 219, 357 

square 357 

square root 357 

stack 174, 181 

stack frame 174 

stack size 119 

standard routines 141, 353-375 
statement-part 262, 264 
statements 301-315 
assigment 302 
case 308 
compound 306 
conditional 306-309 
current (see execution finger) 
for 311 
goto 303 
if 307 

next (see execution finger) 

procedure 302 

repeat 309 

repetitive 309-313 

simple 302 

structured 305 

syntax 301 

while 310 

with 313 

Step Into 124, 127, 247 
Step Out 124, 127, 248 
Step Over 124, 127, 247 
Step-Step 124, 127, 247 
Stop Signs 124-126 

from Instant window 129 
ignoring all 126 
putting in 125 
removing 126 

stopping programs 115-116, 122 
Stops In 125, 251 
string types 273, 278 


string types, in resource descriptions 4l6 
stringof 128, 370 
strings 278-279, 284 

checking index bounds 210 

comparing 296 

in resource descriptions 438 

length attribute 278 

null 279 

ordering 279 

referring to characters 285 
representation 177 
routines 360-363, 370, 371 
size attribute 278 
syntax 260 
StripAddress 177 
structured statements 305 
structured-type 272 
subrange types 270 
subroutine call chain 188 
subset of 295 
subtraction 292 
succ 360 
successor 267 
superset of 295 

switch data, in resource descriptions 423 
switch types, in resource descriptions 419 
Symantec Programming Languages Association 12 
symbolic names 

in resource description statements 425 
symbolic names, in SARez 421 
Synch 372 
syntax errors 79 

syntax, of resource description statments 409 
syntax,checking 117 
sysheap attribute 411 
System 7.0 467 

running under 119 

T 

tag-field 275 
tan 219 
tanh 219 
term 290 

TerminateProfile 393 
Text 254, 277 
Text Only 88 
Text Window 117 
options 119 
printing 119 
routines 363 
saving to file 119 
using in applications 150 
than 307 

THINK C 102, 183, 238 


577 



THINK Pascal User Manual 


THINK Class Library 

memory requirements 5 
THINK Pascal tree 96 
THINK Reference 10 
THINK_Pascal 2l6, 398 
THINK_Pascal_Version_4 216 
thumbs down icon 114 
$$Time 437 
Time Manager 145 
timing routines (see profiler) 
title bar 

Command-clicking 82 
Command-Option-clicking 82 
Option-clicking 76 
TMON 129 
tokens 257 
Toolbox 

calling routines 142 
debugging routines 201 
interfaces 142-143, 488 
interfaces,built-in 142 
intializing 211 
routines not in ROM 142 
ToolScratch 167, 168 
Trace 247 

Tracing compiler directive 208 
tracing programs 124 
Transfer... 227 

trap intercept routines,in code resources 170 
trap intercept routines,in drivers 156 
trash 188 

trash icon (see LightsBug, trash) 
tree 96 

triple-clicking 
on lines 81 
trunc 219, 355 
$$Type 411, 438 
type 266 

type casting 276, 301 
in LightsBug 195 
type casting, in LightsBug 188 
type coercion 276 
type compatibility 281 
type identity 280 
type statement 413 
example 420 
type-check disabling 326 
type-declaration 266 
type-declaration-part 263, 282 
types 176-179, 266-283 
array 178, 273 
boolean 177, 268 
char 177, 269 
classes 277-278 


computational 177 
conversion routines 355-356 
double 177 

enumerated 177, 269-270 
extended 177 
file 179, 277 
in libraries 137 
integer 176, 268 
longint 176 
numbers 259 
objects 277-278 
ordinal 267-270 
packed array 178, 273 
packed record 178, 485 
pointers 177, 279-280 
public 137 
real 177, 271-272 
record 178, 274-276 
set 179, 276-277 
simple 267-272 
string 177, 278-279 
structured 272-278 
subrange 270 
using in other units 132 
Types box, SADeRez 459 
Types Files... button 455 
types, in resource descriptions 414 
align 417 
array 418 
Boolean 415 
character 415 
cstring 4l6 
example 420 
fill 417 
numeric 414 
point 417 
pstring 4l6 
rectangle 417 
string 4l6 
switch 419 
wstring 4l6 

u 

unary operations 287 
unchanged attribute 412 
Undo 80, 228 
union 294 

units 131-136, 327-331 
opening 76 
syntax 328 

unit dependencies 330 
using 131 

using in other units 132 
writing 132 


578 



Index 


univ qualifier 326 

UnloadA4Seg 162, 169 

unlocked attribute 412 

unpack 476 

unprotected attribute 412 

unsigned-constant 289 

until 309 

$USES 404 

uses option 217 

uses clause 132, 134-136, 329 

USES Extensions option 134, 217 

V 

$V 209 

value parameters 182, 321, 322 
using @ 297 
var parameter 182 
variable display 187,191 
variable parameters 321, 322 
using @ 298 

variable-declaration 283 
variable-declaration-part 263 
variable-reference 283 
variables 283-287 

compile-time 214 
compiler 216 
declaring 283 

display format in LightsBug 191 
editing, in LightsBug 193 
examining in LightsBug 191, 192, 194 
in libraries 139 

in preprocessor directives 432 

public 139 

qualified 284 

referring to 283 

SARez string variables 411 

scope 264 

scope in LightsBug 191 
using in other units 132 
variables, in resource descriptions 436 
variant 275 

variant records 275-276 
variant-part 275 
$$Version 437 
View Options... 110, 132, 244 

w 

watchpoints 187, 194 
WDEF resource 164 
$$Weekday 438 
while statements 310 
exiting 368 

Whole Words option 84 

Width of decompiled strings option 459 


WIND resource 

sample window resource file 424 
windows 76 

arranging 77 

automatically opening 77 
hiding 77 
opening 77 
saving positions 77 
WInlineF 373 
Wirth, Niklaus 9 
with statements 286, 313 
$$Word () 426, 438 
word-symbols (see reserved words) 
write 339, 344 

Write Rez 1.0 compatible output option 459 
WriteDraw 370 
writeln 347 

wstring type, in resource descriptions 416 

x 

XCMD resource 164 
XFCN resource 164 

Y 

$$Year438 

z 

zone 

zone size 119 
zones 174 

examining, in LightsBug 197 


579 









SYMANTEC. 


Symantec Corporation 
10201 Torre Avenue 
Cupertino, CA 95014-2132 
408/253-9600 


Symantec and THINK Pascal are trademarks of Symantec Corporation. Other brands and products are trademarks of their respective holders. 
© 1991 Symantec Corporation. All rights reserved. Printed in the U.S.A. 


05-30-00 
TP006f